summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Manifest66
-rw-r--r--README126
-rw-r--r--Read-Manifest-Now0
-rw-r--r--Roadmap44
-rw-r--r--WHATSNEW.txt99
-rw-r--r--docs/NT4_PlainPassword.reg11
-rw-r--r--docs/THANKS22
-rw-r--r--docs/Win95_PlainPassword.reg4
-rw-r--r--docs/announce61
-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.html239
-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/history43
-rw-r--r--docs/manpages/make_smbcodepage.1131
-rw-r--r--docs/manpages/nmbd.8487
-rw-r--r--docs/manpages/samba.760
-rw-r--r--docs/manpages/smb.conf.51981
-rw-r--r--docs/manpages/smbclient.1333
-rw-r--r--docs/manpages/smbd.8175
-rw-r--r--docs/manpages/smbmnt.896
-rw-r--r--docs/manpages/smbmount.844
-rw-r--r--docs/manpages/smbpasswd.8138
-rw-r--r--docs/manpages/smbrun.126
-rw-r--r--docs/manpages/smbstatus.168
-rw-r--r--docs/manpages/smbtar.1102
-rw-r--r--docs/manpages/smbumount.828
-rw-r--r--docs/manpages/testparm.127
-rw-r--r--docs/manpages/testprns.137
-rw-r--r--docs/samba.lsm8
-rw-r--r--docs/textdocs/Application_Serving.txt59
-rw-r--r--docs/textdocs/BROWSING-Config.txt218
-rw-r--r--docs/textdocs/BROWSING.txt572
-rw-r--r--docs/textdocs/BUGS.txt49
-rw-r--r--docs/textdocs/CVS_ACCESS.txt124
-rw-r--r--docs/textdocs/DHCP-Server-Configuration.txt203
-rw-r--r--docs/textdocs/DIAGNOSIS.txt122
-rw-r--r--docs/textdocs/DNIX.txt3
-rw-r--r--docs/textdocs/DOMAIN.txt368
-rw-r--r--docs/textdocs/DOMAIN_CONTROL.txt121
-rw-r--r--docs/textdocs/ENCRYPTION.txt163
-rw-r--r--docs/textdocs/Faxing.txt223
-rw-r--r--docs/textdocs/GOTCHAS.txt71
-rw-r--r--docs/textdocs/HINTS.txt12
-rw-r--r--docs/textdocs/INSTALL.sambatar6
-rwxr-xr-xdocs/textdocs/MIRRORS.txt6
-rw-r--r--docs/textdocs/Macintosh_Clients.txt26
-rw-r--r--docs/textdocs/NTDOMAIN.txt155
-rw-r--r--docs/textdocs/NetBIOS.txt155
-rw-r--r--docs/textdocs/OS2-Client-HOWTO.txt64
-rw-r--r--docs/textdocs/PRINTER_DRIVER.txt240
-rw-r--r--docs/textdocs/PROFILES.txt388
-rw-r--r--docs/textdocs/PROJECTS48
-rw-r--r--docs/textdocs/Passwords.txt13
-rw-r--r--docs/textdocs/Printing.txt132
-rw-r--r--docs/textdocs/README.DCEDFS9
-rw-r--r--docs/textdocs/README.jis31
-rw-r--r--docs/textdocs/README.sambatar8
-rw-r--r--docs/textdocs/Recent-FAQs.txt289
-rw-r--r--docs/textdocs/RoutedNetworks.txt67
-rw-r--r--docs/textdocs/SCO.txt12
-rw-r--r--docs/textdocs/SMBTAR.notes8
-rw-r--r--docs/textdocs/SSLeay.txt392
-rw-r--r--docs/textdocs/Speed.txt83
-rw-r--r--docs/textdocs/Speed2.txt60
-rw-r--r--docs/textdocs/Support.txt2196
-rw-r--r--docs/textdocs/Tracing.txt96
-rw-r--r--docs/textdocs/UNIX-SMB.txt52
-rw-r--r--docs/textdocs/UNIX_INSTALL.txt345
-rw-r--r--docs/textdocs/UNIX_SECURITY.txt53
-rw-r--r--docs/textdocs/Win95.txt77
-rw-r--r--docs/textdocs/WinNT.txt71
-rw-r--r--docs/textdocs/cifsntdomain.txt1501
-rw-r--r--docs/textdocs/security_level.txt99
-rw-r--r--examples/README13
-rw-r--r--examples/autofs/auto.a18
-rw-r--r--examples/autofs/mount-smb.doc65
-rw-r--r--examples/autofs/mount.smb441
-rw-r--r--examples/misc/extra_smbstatus35
-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-redir43
-rw-r--r--examples/printer-accounting/lp-acct38
-rw-r--r--examples/printer-accounting/printcap22
-rwxr-xr-xexamples/printing/smbprint2
-rw-r--r--examples/simple/smb.conf6
-rw-r--r--examples/smb.conf.default250
-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.combin0 -> 9792 bytes
-rw-r--r--packaging/README34
-rw-r--r--packaging/RedHat/README11
-rwxr-xr-xpackaging/RedHat/findsmb141
-rw-r--r--packaging/RedHat/makefile-path.patch43
-rw-r--r--packaging/RedHat/makerpms.sh.tmpl14
-rw-r--r--packaging/RedHat/samba.log11
-rw-r--r--packaging/RedHat/samba.pamd2
-rw-r--r--packaging/RedHat/samba2.spec.tmpl274
-rw-r--r--packaging/RedHat/smb.conf281
-rwxr-xr-xpackaging/RedHat/smb.init49
-rwxr-xr-xpackaging/RedHat/smbadduser73
-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.pl262
-rwxr-xr-xpackaging/SGI/inetd.sh29
-rw-r--r--packaging/SGI/legal_notice.html53
-rwxr-xr-xpackaging/SGI/makefile.pl38
-rwxr-xr-xpackaging/SGI/mkman27
-rwxr-xr-xpackaging/SGI/mkprintcap.sh15
-rwxr-xr-xpackaging/SGI/mkrelease.sh82
-rw-r--r--packaging/SGI/printcap5
-rw-r--r--packaging/SGI/relnotes.html233
-rw-r--r--packaging/SGI/samba.config1
-rw-r--r--packaging/SGI/samba.rc42
-rw-r--r--packaging/SGI/sambalp150
-rw-r--r--packaging/SGI/smb.conf122
-rw-r--r--packaging/SGI/smbpasswd1
-rw-r--r--packaging/SGI/smbprint54
-rwxr-xr-xpackaging/SGI/spec.pl87
-rwxr-xr-xpackaging/SGI/startswat.sh21
-rw-r--r--packaging/Solaris/pkg-specs/Packaging.script5
-rw-r--r--packaging/Solaris/pkg-specs/mkprototype31
-rw-r--r--packaging/Solaris/pkg-specs/pkginfo12
-rw-r--r--packaging/Solaris/pkg-specs/postinstall37
-rw-r--r--packaging/Solaris/pkg-specs/postremove30
-rw-r--r--packaging/SuSE/5.2/samba-1.9.18p5.dif234
-rw-r--r--packaging/SuSE/5.2/samba.spec122
-rw-r--r--source/.cvsignore34
-rw-r--r--source/Makefile.in445
-rw-r--r--source/acconfig.h71
-rw-r--r--source/aclocal.m436
-rw-r--r--source/architecture.doc134
-rw-r--r--source/auth/pass_check.c915
-rw-r--r--source/bin/.cvsignore14
-rw-r--r--source/change-log12
-rw-r--r--source/client/.cvsignore0
-rw-r--r--source/client/client.c3478
-rw-r--r--source/client/clientutil.c976
-rw-r--r--source/client/clitar.c1637
-rw-r--r--source/client/smbmnt.c285
-rw-r--r--source/client/smbmount.c843
-rw-r--r--source/client/smbumount.c175
-rw-r--r--source/codepages/.cvsignore0
-rw-r--r--source/codepages/codepage_def.43770
-rw-r--r--source/codepages/codepage_def.73758
-rw-r--r--source/codepages/codepage_def.85054
-rw-r--r--source/codepages/codepage_def.85263
-rw-r--r--source/codepages/codepage_def.861135
-rw-r--r--source/codepages/codepage_def.866168
-rw-r--r--source/codepages/codepage_def.93224
-rw-r--r--source/codepages/codepage_def.93624
-rw-r--r--source/codepages/codepage_def.94924
-rw-r--r--source/codepages/codepage_def.95024
-rwxr-xr-xsource/config.guess627
-rwxr-xr-xsource/config.sub1099
-rwxr-xr-xsource/configure6046
-rw-r--r--source/configure.in863
-rw-r--r--source/include/.cvsignore1
-rw-r--r--source/include/byteorder.h165
-rw-r--r--source/include/charset.h26
-rw-r--r--source/include/client.h107
-rw-r--r--source/include/config.h.in515
-rw-r--r--source/include/dlinklist.h56
-rw-r--r--source/include/includes.h1327
-rw-r--r--source/include/kanji.h91
-rw-r--r--source/include/local.h113
-rw-r--r--source/include/nameserv.h507
-rw-r--r--source/include/ntdomain.h132
-rw-r--r--source/include/nterr.h507
-rw-r--r--source/include/proto.h2221
-rw-r--r--source/include/rpc_dce.h219
-rw-r--r--source/include/rpc_lsa.h288
-rw-r--r--source/include/rpc_misc.h278
-rw-r--r--source/include/rpc_netlogon.h375
-rw-r--r--source/include/rpc_reg.h141
-rw-r--r--source/include/rpc_samr.h1023
-rw-r--r--source/include/rpc_srvsvc.h576
-rw-r--r--source/include/rpc_wkssvc.h73
-rw-r--r--source/include/rpcclient.h120
-rw-r--r--source/include/smb.h1468
-rw-r--r--source/include/stamp-h.in1
-rw-r--r--source/include/trans2.h14
-rw-r--r--source/include/version.h2
-rwxr-xr-xsource/install-sh238
-rw-r--r--source/internals.doc212
-rw-r--r--source/lib/.cvsignore0
-rw-r--r--source/lib/access.c486
-rw-r--r--source/lib/bitmap.c130
-rw-r--r--source/lib/charcnv.c190
-rw-r--r--source/lib/charset.c361
-rw-r--r--source/lib/debug.c588
-rw-r--r--source/lib/fault.c52
-rw-r--r--source/lib/genrand.c226
-rw-r--r--source/lib/getsmbpass.c32
-rw-r--r--source/lib/interface.c382
-rw-r--r--source/lib/kanji.c514
-rw-r--r--source/lib/md4.c447
-rw-r--r--source/lib/membuffer.c358
-rw-r--r--source/lib/netatalk.c159
-rw-r--r--source/lib/netmask.c353
-rw-r--r--source/lib/pidfile.c95
-rw-r--r--source/lib/replace.c295
-rw-r--r--source/lib/signal.c102
-rw-r--r--source/lib/slprintf.c111
-rw-r--r--source/lib/smbrun.c178
-rw-r--r--source/lib/system.c534
-rw-r--r--source/lib/time.c546
-rw-r--r--source/lib/ufc.c17
-rw-r--r--source/lib/username.c335
-rw-r--r--source/lib/util.c5002
-rw-r--r--source/lib/util_hnd.c289
-rw-r--r--source/libsmb/.cvsignore0
-rw-r--r--source/libsmb/clientgen.c1905
-rw-r--r--source/libsmb/credentials.c222
-rw-r--r--source/libsmb/namequery.c575
-rw-r--r--source/libsmb/nmblib.c713
-rw-r--r--source/libsmb/nterr.c543
-rw-r--r--source/libsmb/pwd_cache.c235
-rw-r--r--source/libsmb/smbdes.c399
-rw-r--r--source/libsmb/smbencrypt.c139
-rw-r--r--source/libsmb/smberr.c181
-rw-r--r--source/locking/locking.c367
-rw-r--r--source/locking/locking_shm.c701
-rw-r--r--source/locking/locking_slow.c1076
-rw-r--r--source/locking/shmem.c893
-rw-r--r--source/locking/shmem_sysv.c720
-rw-r--r--source/lsarpcd/srv_lsa.c497
-rw-r--r--source/md4.h58
-rw-r--r--source/nameserv.c2318
-rw-r--r--source/nmbd/.cvsignore0
-rw-r--r--source/nmbd/asyncdns.c349
-rw-r--r--source/nmbd/nmbd.c771
-rw-r--r--source/nmbd/nmbd_become_dmb.c394
-rw-r--r--source/nmbd/nmbd_become_lmb.c610
-rw-r--r--source/nmbd/nmbd_browserdb.c185
-rw-r--r--source/nmbd/nmbd_browsesync.c617
-rw-r--r--source/nmbd/nmbd_elections.c385
-rw-r--r--source/nmbd/nmbd_incomingdgrams.c816
-rw-r--r--source/nmbd/nmbd_incomingrequests.c622
-rw-r--r--source/nmbd/nmbd_lmhosts.c101
-rw-r--r--source/nmbd/nmbd_logonnames.c170
-rw-r--r--source/nmbd/nmbd_mynames.c204
-rw-r--r--source/nmbd/nmbd_namelistdb.c637
-rw-r--r--source/nmbd/nmbd_namequery.c265
-rw-r--r--source/nmbd/nmbd_nameregister.c395
-rw-r--r--source/nmbd/nmbd_namerelease.c238
-rw-r--r--source/nmbd/nmbd_nodestatus.c99
-rw-r--r--source/nmbd/nmbd_packets.c1959
-rw-r--r--source/nmbd/nmbd_processlogon.c243
-rw-r--r--source/nmbd/nmbd_responserecordsdb.c267
-rw-r--r--source/nmbd/nmbd_sendannounce.c610
-rw-r--r--source/nmbd/nmbd_serverlistdb.c458
-rw-r--r--source/nmbd/nmbd_subnetdb.c359
-rw-r--r--source/nmbd/nmbd_synclists.c290
-rw-r--r--source/nmbd/nmbd_winsproxy.c224
-rw-r--r--source/nmbd/nmbd_winsserver.c1612
-rw-r--r--source/nmbd/nmbd_workgroupdb.c366
-rw-r--r--source/nmbsync.c303
-rw-r--r--source/param/.cvsignore0
-rw-r--r--source/param/loadparm.c1858
-rw-r--r--source/param/params.c862
-rw-r--r--source/parsing.doc181
-rw-r--r--source/passdb/ldap.c997
-rw-r--r--source/passdb/nispass.c697
-rw-r--r--source/passdb/pass_check.c915
-rw-r--r--source/passdb/passdb.c889
-rw-r--r--source/passdb/smbpass.c1211
-rw-r--r--source/passdb/smbpassfile.c320
-rw-r--r--source/printing/.cvsignore0
-rw-r--r--source/printing/pcap.c48
-rw-r--r--source/printing/print_svid.c121
-rw-r--r--source/printing/printing.c863
-rw-r--r--source/rpc_client/cli_login.c191
-rw-r--r--source/rpc_client/cli_lsarpc.c255
-rw-r--r--source/rpc_client/cli_netlogon.c639
-rw-r--r--source/rpc_client/cli_pipe.c699
-rw-r--r--source/rpc_client/cli_samr.c705
-rw-r--r--source/rpc_client/cli_srvsvc.c411
-rw-r--r--source/rpc_client/cli_wkssvc.c90
-rw-r--r--source/rpc_client/ntclienttrust.c167
-rw-r--r--source/rpc_parse/.cvsignore0
-rw-r--r--source/rpc_parse/parse_lsa.c571
-rw-r--r--source/rpc_parse/parse_misc.c966
-rw-r--r--source/rpc_parse/parse_net.c1050
-rw-r--r--source/rpc_parse/parse_prs.c276
-rw-r--r--source/rpc_parse/parse_reg.c264
-rw-r--r--source/rpc_parse/parse_rpc.c529
-rw-r--r--source/rpc_parse/parse_samr.c2680
-rw-r--r--source/rpc_parse/parse_srv.c1440
-rw-r--r--source/rpc_parse/parse_wks.c145
-rw-r--r--source/rpc_server/.cvsignore0
-rw-r--r--source/rpc_server/srv_ldap_helpers.c14
-rw-r--r--source/rpc_server/srv_lsa.c497
-rw-r--r--source/rpc_server/srv_lsa_hnd.c289
-rw-r--r--source/rpc_server/srv_netlog.c875
-rw-r--r--source/rpc_server/srv_pipe_hnd.c340
-rw-r--r--source/rpc_server/srv_reg.c240
-rw-r--r--source/rpc_server/srv_samr.c1311
-rw-r--r--source/rpc_server/srv_srvsvc.c1066
-rw-r--r--source/rpc_server/srv_util.c496
-rw-r--r--source/rpc_server/srv_wkssvc.c112
-rw-r--r--source/rpcclient/cmd_lsarpc.c119
-rw-r--r--source/rpcclient/cmd_netlogon.c108
-rw-r--r--source/rpcclient/cmd_samr.c587
-rw-r--r--source/rpcclient/cmd_srvsvc.c329
-rw-r--r--source/rpcclient/cmd_wkssvc.c95
-rw-r--r--source/rpcclient/display.c1013
-rw-r--r--source/rpcclient/rpcclient.c756
-rw-r--r--source/script/.cvsignore0
-rw-r--r--source/script/addtosmbpass6
-rwxr-xr-xsource/script/installbin.sh16
-rwxr-xr-xsource/script/installcp.sh38
-rwxr-xr-xsource/script/installman.sh40
-rwxr-xr-xsource/script/installscripts.sh46
-rwxr-xr-xsource/script/installswat.sh57
-rwxr-xr-xsource/script/mknissmbpasswd.sh31
-rwxr-xr-xsource/script/mknissmbpwdtbl.sh42
-rw-r--r--source/script/mkproto.awk116
-rwxr-xr-xsource/script/mksmbpasswd.sh2
-rwxr-xr-xsource/script/revert.sh13
-rw-r--r--source/script/smbtar24
-rwxr-xr-xsource/script/uninstallbin.sh42
-rwxr-xr-xsource/script/uninstallcp.sh33
-rwxr-xr-xsource/script/uninstallman.sh29
-rwxr-xr-xsource/script/uninstallscripts.sh36
-rwxr-xr-xsource/smbadduser73
-rw-r--r--source/smbd/.cvsignore0
-rw-r--r--source/smbd/blocking.c624
-rw-r--r--source/smbd/chgpasswd.c431
-rw-r--r--source/smbd/close.c183
-rw-r--r--source/smbd/conn.c189
-rw-r--r--source/smbd/connection.c224
-rw-r--r--source/smbd/dfree.c229
-rw-r--r--source/smbd/dir.c669
-rw-r--r--source/smbd/dosmode.c259
-rw-r--r--source/smbd/error.c146
-rw-r--r--source/smbd/fileio.c129
-rw-r--r--source/smbd/filename.c729
-rw-r--r--source/smbd/files.c496
-rw-r--r--source/smbd/groupname.c243
-rw-r--r--source/smbd/ipc.c2408
-rw-r--r--source/smbd/mangle.c1254
-rw-r--r--source/smbd/message.c71
-rw-r--r--source/smbd/negprot.c419
-rw-r--r--source/smbd/nttrans.c1467
-rw-r--r--source/smbd/open.c1179
-rw-r--r--source/smbd/oplock.c1085
-rw-r--r--source/smbd/password.c1650
-rw-r--r--source/smbd/pipes.c158
-rw-r--r--source/smbd/predict.c162
-rw-r--r--source/smbd/process.c940
-rw-r--r--source/smbd/quotas.c666
-rw-r--r--source/smbd/reply.c3657
-rw-r--r--source/smbd/server.c4566
-rw-r--r--source/smbd/service.c542
-rw-r--r--source/smbd/ssl.c265
-rw-r--r--source/smbd/trans2.c1580
-rw-r--r--source/smbd/uid.c423
-rw-r--r--source/smbd/vt_mode.c496
-rw-r--r--source/tests/.cvsignore0
-rw-r--r--source/tests/README10
-rw-r--r--source/tests/fcntl_lock.c78
-rw-r--r--source/tests/ftruncate.c24
-rw-r--r--source/tests/getgroups.c62
-rw-r--r--source/tests/shared_mmap.c66
-rw-r--r--source/tests/summary.c33
-rw-r--r--source/tests/sysv_ipc.c86
-rw-r--r--source/tests/trapdoor.c25
-rw-r--r--source/tests/trivial.c4
-rw-r--r--source/ubiqx/.cvsignore0
-rw-r--r--source/ubiqx/COPYING.LIB481
-rw-r--r--source/ubiqx/README.UBI18
-rw-r--r--source/ubiqx/sys_include.h51
-rw-r--r--source/ubiqx/ubi_BinTree.c1080
-rw-r--r--source/ubiqx/ubi_BinTree.h800
-rw-r--r--source/ubiqx/ubi_Cache.c502
-rw-r--r--source/ubiqx/ubi_Cache.h409
-rw-r--r--source/ubiqx/ubi_SplayTree.c509
-rw-r--r--source/ubiqx/ubi_SplayTree.h371
-rw-r--r--source/ubiqx/ubi_dLinkList.c165
-rw-r--r--source/ubiqx/ubi_dLinkList.h236
-rw-r--r--source/ubiqx/ubi_sLinkList.c181
-rw-r--r--source/ubiqx/ubi_sLinkList.h248
-rw-r--r--source/utils/make_printerdef.c510
-rw-r--r--source/utils/make_smbcodepage.c472
-rw-r--r--source/utils/nmblookup.c155
-rw-r--r--source/utils/smbpasswd.c958
-rw-r--r--source/utils/smbrun.c (renamed from source/smbd/smbrun.c)74
-rw-r--r--source/utils/status.c363
-rw-r--r--source/utils/testparm.c62
-rw-r--r--source/utils/testprns.c10
-rw-r--r--source/utils/torture.c986
-rw-r--r--source/web/.cvsignore0
-rw-r--r--source/web/cgi.c526
-rw-r--r--source/web/diagnose.c67
-rw-r--r--source/web/startstop.c104
-rw-r--r--source/web/statuspage.c260
-rw-r--r--source/web/swat.c676
-rw-r--r--swat/README126
-rw-r--r--swat/help/parameters.html2260
-rw-r--r--swat/help/welcome.html74
-rw-r--r--swat/images/background.gifbin0 -> 34618 bytes
-rw-r--r--swat/images/background.jpgbin0 -> 11726 bytes
-rw-r--r--swat/images/globals.gifbin0 -> 376 bytes
-rw-r--r--swat/images/home.gifbin0 -> 391 bytes
-rw-r--r--swat/images/printers.gifbin0 -> 377 bytes
-rw-r--r--swat/images/samba.gifbin0 -> 3643 bytes
-rw-r--r--swat/images/shares.gifbin0 -> 440 bytes
-rw-r--r--swat/images/status.gifbin0 -> 412 bytes
-rw-r--r--swat/images/viewconfig.gifbin0 -> 365 bytes
-rw-r--r--swat/include/footer.html3
-rw-r--r--swat/include/header.html10
439 files changed, 137602 insertions, 23097 deletions
diff --git a/Manifest b/Manifest
new file mode 100644
index 00000000000..7e8dc0106f6
--- /dev/null
+++ b/Manifest
@@ -0,0 +1,66 @@
+Copyright (C) 1997 - Samba-Team
+
+The Samba package you have just unpacked contains the following:
+
+Directory Notes:
+========= ======
+docs (Samba Documentation):
+--------------------------------------
+
+ The Samba documentation for 1.9.17 has had some of its content
+ updated and a new structure has been put in place. However, since
+ this is all rather new the documentation format of previous
+ versions will remain in place.
+
+ Note in particular two files - <your OS>_INSTALL.txt and 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.
+
+ You pay close attention to all the files with a
+ .txt extension. Most problems can be solved by reference to the
+ two files mentioned.
+
+ The new 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 only for RedHat Linux. 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:
+ samba.anu.edu.au/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. Also, you must edit the enclosed "Makefile" as required
+ for your operating system platform. Then just run:
+ a) make
+ b) make install
+ then
+ c) 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..14c2eac661b 100644
--- a/README
+++ b/README
@@ -1,4 +1,6 @@
-This is version 1.9 of Samba, the free SMB client and server for unix.
+This is version 2.0.0alphaX 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.
@@ -7,54 +9,108 @@ 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 is what the new SMB initiative is
+called. For details watch http://samba.anu.edu.au/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 among 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
+For a much better overview have a look at the web site at
+http://samba.anu.edu.au/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.anu.edu.au/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.anu.edu.au. 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.anu.edu.au/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.anu.edu.au/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.anu.edu.au
3 Ballow Crescent
Macgregor, A.C.T.
2615 Australia
+Samba Team
+Email: samba-bugs@samba.anu.edu.au
MORE INFO
=========
@@ -64,26 +120,36 @@ 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.
+
+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://samba.anu.edu.au/listproc/samba-docs.
FTP SITE
--------
-The main anonymous ftp distribution site for this software is
-nimbus.anu.edu.au in the directory pub/tridge/samba/.
+Please use a mirror site! The list of mirrors is in docs/MIRRORS.txt.
+The master ftp site is samba.anu.edu.au in the directory pub/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.anu.edu.au 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.anu.edu.au with a
+body of "subscribe samba-announce Your Name". All announcements also
+go to the samba list.
NEWS GROUP
@@ -94,7 +160,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 +168,12 @@ 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.anu.edu.au/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? :-)
+It is maintained by Paul Blackman (thanks Paul!). You can contact him
+at ictinus@samba.anu.edu.au.
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..4531a34e031
--- /dev/null
+++ b/Roadmap
@@ -0,0 +1,44 @@
+Copyright (C) 1997-1998 - Samba-Team
+
+The Samba-Team are committed to an agressive program to deliver quality
+controlled software to a well defined roadmap.
+
+The current Samba release 1.9.18 is called the "Oplock Release"
+The following development objectives are in place:
+----------------------------------------------------------------------------
+Please Note: Development of the 1.9.19 and 1.9.20 releases is presently
+ well ahead of schedule. This means that the release program
+ may very well change radically from what is outlined below.
+
+ If present developments continue then 1.9.19 will feature
+ improved authentication and security capabilities as well as
+ the long promised GUI (Web) based management tools.
+
+ This being the case, then version 2.0 may become the long
+ awaited Windows NT Domain Controller Release and version 2.1
+ will become the Directory Services update.
+
+ Should 1.9.19 roll out ahead of schedule then there will
+ likely be a delay of up to 6 months before the NT Domain
+ Controller release will be ready for prime-time business use.
+----------------------------------------------------------------------------
+
+Version / Codename Notes
+------------------ ----------------------------------------------------
+1.9.19 An authentication update release to offer improved
+"Auth Code Release" security and password synchronisation capabilities.
+ Also, support for Windows NT specific SMB calls.
+
+1.9.20 Introduction of new managment tools
+"GUI Config Release" Improved multi-language support.
+
+2.0 The next generation Directory Services update
+"DSA Release"
+
+While no release date or content promises are made we are hoping to release
+the remainder of the 1.9 series relases within short time frame.
+
+Should a budding contributor spring into gear and deliver any of the above
+ahead of the above release sequence then we reserve the option to make an
+out of sequence release (but always keeping to a logical sequence code number).
+
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
new file mode 100644
index 00000000000..b8ac9939f84
--- /dev/null
+++ b/WHATSNEW.txt
@@ -0,0 +1,99 @@
+ WHATS NEW IN 2.0.0 ALPHA SERIES
+ ===============================
+
+This is an alpha release of Samba. Releases in this series are done
+automatically every week based on the latest code in the Samba CVS
+tree.
+
+THIS RELEASE IS NOT PRODUCTION QUALITY. IT MAY NOT EVEN COMPILE.
+
+If you use this release then be aware of the following:
+
+- only use these releases if you can't use CVS for some
+ reason. Getting the code via anonymous cvs is preferable. See
+ http://samba.anu.edu.au/cvs.html
+
+- don't use this code if you are not an experienced programmer. We are
+ doing these releases so that users who cannot access the CVS tree
+ directly for some reason can report/fix bugs. If you find bugs in
+ this release and you want to help fix them then please join the
+ samba-technical mailing list (see http://samba.anu.edu.au/listproc/)
+ and discuss it there.
+
+- the docs are not uptodate. If you find documentation errors then
+ please send patches to fix them. Out of date documentation is one of
+ the main things holding back a Samba 2.0 release.
+
+Major changes in Samba 2.0
+--------------------------
+
+There have been several major changes in Samba for version 2.0. Here
+are some of them:
+
+1) autoconf
+-----------
+
+You now configure Samba by running "./configure" then make. See
+docs/UNIX_INSTALL.txt
+
+2) domain control
+-----------------
+
+Samba can now (mostly) act as a NT primary domain controller and
+domain logon server. Unfortunately this is largely undocumented at the
+moment, but to get you started you want smb.conf entries like this:
+
+ domain controller = Yes
+ domain logons = Yes
+ preferred master = Yes
+ domain master = Yes
+
+[netlogon]
+ path = /data/netlogon
+ read only = No
+
+further documentation on this still needs to be written :)
+
+3) option defaults changed
+--------------------------
+
+several parameters have changed their default values. The most
+important of these is that the default security mode is now user level
+security rather than share level security.
+
+4) web based GUI configuration
+------------------------------
+
+Samba now comes with SWAT, a web based GUI config system. See
+swat/README for how to set it up.
+
+5) change to nmbd default logging behavior
+------------------------------------------
+
+The nmbd daemon now appends to pre-existing log files by default. In
+previous releases, nmbd would overwrite old log files. Both nmbd and smbd
+now accept the '-a' and '-o' options, which mean "append" and "overwrite",
+respectively.
+
+
+Minor changes in Samba 2.0
+--------------------------
+
+1) timestamps on all log messages
+---------------------------------
+
+Both nmbd and smbd now place timestamp headers on all log messages. The
+headers include the time and the message level. On systems with compilers
+that support the necessary macros, the file & function names and the line
+number (of the call to Debug()) will also be listed.
+
+2) NetBIOS name server has improved database
+--------------------------------------------
+
+The linked list used to store NetBIOS names in the Samba "WINS" database
+has been replaced with a splay-balanced binary tree. This should improve
+speed for installations with very large WINS lists.
+
+
+There have been lots of other changes as well. We'll add them here as
+we remember them :)
diff --git a/docs/NT4_PlainPassword.reg b/docs/NT4_PlainPassword.reg
new file mode 100644
index 00000000000..b30db150c24
--- /dev/null
+++ b/docs/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/THANKS b/docs/THANKS
index 6405da3f9f4..19c11dc432f 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.anu.edu.au/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/Win95_PlainPassword.reg b/docs/Win95_PlainPassword.reg
new file mode 100644
index 00000000000..9dd3103689c
--- /dev/null
+++ b/docs/Win95_PlainPassword.reg
@@ -0,0 +1,4 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\VNETSUP]
+"EnablePlainTextPassword"=dword:00000001
diff --git a/docs/announce b/docs/announce
index f761320f43e..7bc0aa8c4c3 100644
--- a/docs/announce
+++ b/docs/announce
@@ -4,21 +4,31 @@
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 Unix SMB client and a netbios nameserver.
+The package also includes a SMB client for accessing other SMB servers,
+and an advanced netbios/WINS nameserver for browsing support.
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,16 +36,16 @@ 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.
+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 1.8?
---------------------
@@ -47,8 +57,9 @@ 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,
+Windows NT and OS/2 come with suitable clients by default.
What network protocols are supported?
-------------------------------------
@@ -66,7 +77,7 @@ 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 +87,12 @@ 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?
-------------
@@ -93,8 +106,8 @@ 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.anu.edu.au in
+the directory pub/samba/.
What about SMBServer?
---------------------
@@ -123,7 +136,7 @@ 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.anu.edu.au/samba/
-Andrew Tridgell (Contact: samba-bugs@anu.edu.au)
-January 1995
+The Samba Team (Contact: samba-bugs@samba.anu.edu.au)
+June 1996
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..731391a9987
--- /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.anu.edu.au/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-bugs@anu.edu.au">samba-bugs@anu.edu.au</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:samba-bugs@anu.edu.au">samba-bugs@anu.edu.au</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 Stratos 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..eadc3e26ede
--- /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.anu.edu.au</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 Stratos 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..020d5322811
--- /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.anu.edu.au</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.anu.edu.au/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-bugs@anu.edu.au" name="samba-bugs@anu.edu.au"> !
+
+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-bugs@anu.edu.au" name="samba-bugs@anu.edu.au">.
+
+<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..80610fb59ed
--- /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.anu.edu.au/[.....]">http://samba.anu.edu.au/[.....]</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..ac760380067
--- /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.anu.edu.au/pub/samba/alpha/change-log">ftp://samba.anu.edu.au/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.anu.edu.au 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.anu.edu.au/samba/">http://samba.anu.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>
+<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.anu.edu.au">listproc@samba.anu.edu.au</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.anu.edu.au">listproc@samba.anu.edu.au</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.anu.edu.au/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-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</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-bugs 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.anu.edu.au. This will be processed more quickly than
+mail to samba-bugs. 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..63adff35f92
--- /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.anu.edu.au/cifs/">http://samba.anu.edu.au/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..5a70808867b
--- /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.anu.edu.au</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..75038f19f53
--- /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.anu.edu.au</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.anu.edu.au/[.....]"> 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.anu.edu.au/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.anu.edu.au 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.anu.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
+ <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.anu.edu.au"
+name="listproc@samba.anu.edu.au">. 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.anu.edu.au" name="listproc@samba.anu.edu.au">. 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.anu.edu.au/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-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">. 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-bugs 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.anu.edu.au. This will be processed more quickly than
+mail to samba-bugs. 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.anu.edu.au/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..65d9a57ff62
--- /dev/null
+++ b/docs/faq/Samba-meta-FAQ.txt
@@ -0,0 +1,924 @@
+ Samba meta FAQ
+ Dan Shearer & Paul Blackman, ictinus@samba.anu.edu.au
+ 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.anu.edu.au/[.....]> 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.anu.edu.au/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.anu.edu.au
+ 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.anu.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 This FAQ and the rest in its family
+
+
+
+ 22..66.. HHooww ddoo II ssuubbssccrriibbee ttoo tthhee SSaammbbaa MMaaiilliinngg LLiissttss??
+
+
+ Send email to listproc@samba.anu.edu.au. 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.anu.edu.au. 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.anu.edu.au/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-bugs@samba.anu.edu.au. 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-bugs 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.anu.edu.au. This will be processed more quickly than mail
+ to samba-bugs. 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.anu.edu.au/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..c010e50e011
--- /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.anu.edu.au/pub/samba/alpha/change-log">ftp://samba.anu.edu.au/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.anu.edu.au. 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.anu.edu.au/pub/samba/docs/">ftp://samba.anu.edu.au/pub/samba/docs/</A>
+<UL>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Application_Serving.txt">Application_Serving.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt">BROWSING.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/BUGS.txt">BUGS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DIAGNOSIS.txt">DIAGNOSIS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DNIX.txt">DNIX.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN.txt">DOMAIN.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN_CONTROL.txt">CONTROL.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt">ENCRYPTION.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Faxing.txt">Faxing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/GOTCHAS.txt">GOTCHAS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/HINTS.txt">HINTS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.sambatar">INSTALL.sambatar</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.txt">INSTALL.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/MIRRORS">MIRRORS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/NetBIOS.txt">NetBIOS.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/OS2.txt">OS2.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/PROJECTS">PROJECTS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Passwords.txt">Passwords.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Printing.txt">Printing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.DCEDFS">README.DCEDFS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.OS2">README.OS2</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.jis">README.jis</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/README.sambatar">README.sambatar</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/SCO.txt">SCO.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/SMBTAR.notes">SMBTAR.notes</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Speed.txt">Speed.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Support.txt">Support.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/THANKS">THANKS</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Tracing.txt">Tracing.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/UNIX-SMB.txt">SMB.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/Warp.txt">Warp.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/WinNT.txt">WinNT.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/history">history</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt">level.txt</A></LI>
+<LI>
+<A HREF="ftp://samba.anu.edu.au/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.anu.edu.au">listproc@samba.anu.edu.au</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.anu.edu.au">listproc@samba.anu.edu.au</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.anu.edu.au/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-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</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..b92a1e2fcd1
--- /dev/null
+++ b/docs/faq/sambafaq-2.html
@@ -0,0 +1,239 @@
+<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
+<A HREF="ftp://samba.anu.edu.au/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.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-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</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-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</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..1b5dcf4d9aa
--- /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.anu.edu.au/samba/binaries/miscellaneous/timesync.pif">http://samba.anu.edu.au/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.anu.edu.au/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.anu.edu.au/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-bugs@samba.anu.edu.au">samba-bugs@samba.anu.edu.au</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.anu.edu.au/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..9c45d524dd3
--- /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.anu.edu.au</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..d306881b56b
--- /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.anu.edu.au</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.anu.edu.au/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.anu.edu.au. 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.anu.edu.au/pub/samba/docs/">
+ <itemize>
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Application_Serving.txt" name="Application_Serving.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt" name="BROWSING.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/BUGS.txt" name="BUGS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DIAGNOSIS.txt" name="DIAGNOSIS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DNIX.txt" name="DNIX.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN.txt" name="DOMAIN.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN_CONTROL.txt" name="CONTROL.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt" name="ENCRYPTION.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Faxing.txt" name="Faxing.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/GOTCHAS.txt" name="GOTCHAS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/HINTS.txt" name="HINTS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.sambatar" name="INSTALL.sambatar">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.txt" name="INSTALL.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/MIRRORS" name="MIRRORS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/NetBIOS.txt" name="NetBIOS.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/OS2.txt" name="OS2.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/PROJECTS" name="PROJECTS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Passwords.txt" name="Passwords.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Printing.txt" name="Printing.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.DCEDFS" name="README.DCEDFS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.OS2" name="README.OS2">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.jis" name="README.jis">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/README.sambatar" name="README.sambatar">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/SCO.txt" name="SCO.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/SMBTAR.notes" name="SMBTAR.notes">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Speed.txt" name="Speed.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Support.txt" name="Support.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/THANKS" name="THANKS">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Tracing.txt" name="Tracing.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/UNIX-SMB.txt" name="SMB.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/Warp.txt" name="Warp.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/WinNT.txt" name="WinNT.txt">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/history" name="history">
+ <item><url url="ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt" name="level.txt">
+ <item><url url="ftp://samba.anu.edu.au/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.anu.edu.au" name="listproc@samba.anu.edu.au">. 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.anu.edu.au" name="listproc@samba.anu.edu.au">. 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.anu.edu.au/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-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">. 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.anu.edu.au/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-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au"> !
+
+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-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">.
+
+<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.anu.edu.au/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.anu.edu.au/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.anu.edu.au/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-bugs@samba.anu.edu.au" name="samba-bugs@samba.anu.edu.au">,
+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.anu.edu.au/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..7108846ae67
--- /dev/null
+++ b/docs/faq/sambafaq.txt
@@ -0,0 +1,1122 @@
+ Samba FAQ
+ Paul Blackman, ictinus@samba.anu.edu.au
+ 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.anu.edu.au/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.anu.edu.au.
+ 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.anu.edu.au/pub/samba/docs/>
+
+ +o Application_Serving.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/Application_Serving.txt>
+
+ +o BROWSING.txt <ftp://samba.anu.edu.au/pub/samba/docs/BROWSING.txt>
+
+ +o BUGS.txt <ftp://samba.anu.edu.au/pub/samba/docs/BUGS.txt>
+
+ +o DIAGNOSIS.txt <ftp://samba.anu.edu.au/pub/samba/docs/DIAGNOSIS.txt>
+
+ +o DNIX.txt <ftp://samba.anu.edu.au/pub/samba/docs/DNIX.txt>
+
+ +o DOMAIN.txt <ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN.txt>
+
+ +o CONTROL.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/DOMAIN_CONTROL.txt>
+
+ +o ENCRYPTION.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/ENCRYPTION.txt>
+
+ +o Faxing.txt <ftp://samba.anu.edu.au/pub/samba/docs/Faxing.txt>
+
+ +o GOTCHAS.txt <ftp://samba.anu.edu.au/pub/samba/docs/GOTCHAS.txt>
+
+ +o HINTS.txt <ftp://samba.anu.edu.au/pub/samba/docs/HINTS.txt>
+
+ +o INSTALL.sambatar
+ <ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.sambatar>
+
+ +o INSTALL.txt <ftp://samba.anu.edu.au/pub/samba/docs/INSTALL.txt>
+
+ +o MIRRORS <ftp://samba.anu.edu.au/pub/samba/docs/MIRRORS>
+
+ +o NetBIOS.txt <ftp://samba.anu.edu.au/pub/samba/docs/NetBIOS.txt>
+
+ +o OS2.txt <ftp://samba.anu.edu.au/pub/samba/docs/OS2.txt>
+
+ +o PROJECTS <ftp://samba.anu.edu.au/pub/samba/docs/PROJECTS>
+
+ +o Passwords.txt <ftp://samba.anu.edu.au/pub/samba/docs/Passwords.txt>
+
+ +o Printing.txt <ftp://samba.anu.edu.au/pub/samba/docs/Printing.txt>
+
+ +o README.DCEDFS <ftp://samba.anu.edu.au/pub/samba/docs/README.DCEDFS>
+
+ +o README.OS2 <ftp://samba.anu.edu.au/pub/samba/docs/README.OS2>
+
+ +o README.jis <ftp://samba.anu.edu.au/pub/samba/docs/README.jis>
+
+ +o README.sambatar
+ <ftp://samba.anu.edu.au/pub/samba/docs/README.sambatar>
+
+ +o SCO.txt <ftp://samba.anu.edu.au/pub/samba/docs/SCO.txt>
+
+ +o SMBTAR.notes <ftp://samba.anu.edu.au/pub/samba/docs/SMBTAR.notes>
+
+ +o Speed.txt <ftp://samba.anu.edu.au/pub/samba/docs/Speed.txt>
+
+ +o Support.txt <ftp://samba.anu.edu.au/pub/samba/docs/Support.txt>
+
+ +o THANKS <ftp://samba.anu.edu.au/pub/samba/docs/THANKS>
+
+ +o Tracing.txt <ftp://samba.anu.edu.au/pub/samba/docs/Tracing.txt>
+
+ +o SMB.txt <ftp://samba.anu.edu.au/pub/samba/docs/UNIX-SMB.txt>
+
+ +o Warp.txt <ftp://samba.anu.edu.au/pub/samba/docs/Warp.txt>
+
+ +o WinNT.txt <ftp://samba.anu.edu.au/pub/samba/docs/WinNT.txt>
+
+ +o history <ftp://samba.anu.edu.au/pub/samba/docs/history>
+
+ +o level.txt
+ <ftp://samba.anu.edu.au/pub/samba/docs/security_level.txt>
+
+ +o slip.htm <ftp://samba.anu.edu.au/pub/samba/docs/wfw_slip.htm>
+
+
+ 11..77.. HHooww ddoo II ssuubbssccrriibbee ttoo tthhee SSaammbbaa MMaaiilliinngg LLiissttss??
+
+
+ Send email to listproc@samba.anu.edu.au. 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.anu.edu.au. 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.anu.edu.au/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-bugs@samba.anu.edu.au. 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.anu.edu.au/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-bugs@samba.anu.edu.au !
+
+ 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-bugs@samba.anu.edu.au.
+
+
+ 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.anu.edu.au/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.anu.edu.au/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.anu.edu.au/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-bugs@samba.anu.edu.au, 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.anu.edu.au/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..dd9e83719ff 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,33 @@ 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.
+---------------------
diff --git a/docs/manpages/make_smbcodepage.1 b/docs/manpages/make_smbcodepage.1
new file mode 100644
index 00000000000..1030821c36d
--- /dev/null
+++ b/docs/manpages/make_smbcodepage.1
@@ -0,0 +1,131 @@
+.TH MAKE_SMBCODEPAGE 1 "19 Sep 1998" "make_smbcodepage 2.0.0-alpha6"
+.SH NAME
+make_smbcodepage \- create a binary codepage definition file from an ascii codepage definition source file, or reverse the process.
+.SH SYNOPSIS
+.B make_smbcodepage
+.I c|d
+.I codepage
+.I inputfile
+.I outputfile
+.SH DESCRIPTION
+This program is part of the Samba suite.
+
+.B make_smbcodepage
+compiles or de-compiles codepage files for use with the internationalization
+features of Samba 1.9.18.
+
+An ascii 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 asynchronous.
+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 maps from plain upper
+case A to plain lower case a when lower casing a character.
+
+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.
+
+As Samba does not yet use UNICODE (current for Samba version 1.9.18)
+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). Ascii codepage definition sample files are provided
+in the Samba distribution for codepages 437 (USA), 850 (Western European)
+852 (MS-DOS Latin 2) and 932 (Kanji SJIS). Users are encouraged to
+write ascii codepage definition files for their own code pages and
+donate them to samba-bugs@samba.anu.edu.au. All codepage files in the
+Samba source directory are compiled and installed when a 'make install'
+command is issued there.
+
+An ascii codepage definition file consists of multiple lines containing
+four fields. These fields are :
+.B lower
+which is the (hex) lower case character mapped on this line.
+.B upper
+which is the (hex) upper case character that the lower case character
+will map to.
+.B map upper to lower
+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.
+.B map lower to upper
+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.
+
+.SH OPTIONS
+.I c|d
+
+.RS 3
+This tells make_smbcodepage if it is compiling (c) an ascii code page file
+to binary, or de-compiling a binary codepage file to ascii.
+.RE
+
+.I codepage
+
+.RS 3
+This is the codepage we are processing (a number, eg. 850)
+.RE
+
+.I inputfile
+
+.RS 3
+This is the input file to process.
+.RE
+
+.I outputfile
+
+.RS 3
+This is the output file to produce.
+.RE
+
+.SH FILES
+.B codepage_def.<codepage>
+.RS 3
+These are the input (ascii) codepage files provided in the Samba
+source/ directory.
+.RE
+.SH FILES
+.B codepage.<codepage>
+.RS 3
+These are the output (binary) codepage files produced and placed in the Samba
+destination lib/codepage/ directory.
+.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 make_smbcodepage
+program be installed under the /usr/local/samba 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.18 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
+.BR smb.conf (5),
+.BR smbd (8)
+
+.SH BUGS
+None known.
+.SH CREDITS
+The
+.B make_smbcodepage
+program was written by Jeremy Allison (jallison@whistle.com) as part of the
+Internationalization effort of the Samba software.
+
+Please send bug reports to samba-bugs@samba.anu.edu.au.
+
+See
+.BR samba (7)
+for a full list of contributors and details on how to
+submit bug reports, comments etc.
diff --git a/docs/manpages/nmbd.8 b/docs/manpages/nmbd.8
index e42f194cdee..0068960b614 100644
--- a/docs/manpages/nmbd.8
+++ b/docs/manpages/nmbd.8
@@ -1,44 +1,29 @@
-.TH NMBD 8 17/1/1995 nmbd nmbd
+.TH NMBD 8 "19 Sep 1998" "nmbd 2.0.0-alpha6"
.SH NAME
nmbd \- provide netbios nameserver support to clients
.SH SYNOPSIS
.B nmbd
[
-.B -B
-.I broadcast address
+.B \-D
] [
-.B -I
-.I IP address
-] [
-.B -D
-] [
-.B -C comment string
-] [
-.B -G
-.I group name
-] [
-.B -H
+.B \-H
.I netbios hosts file
] [
-.B -N
-.I netmask
-] [
-.B -d
+.B \-d
.I debuglevel
] [
-.B -l
+.B \-l
.I log basename
] [
-.B -n
+.B \-n
.I netbios name
] [
-.B -p
+.B \-p
.I port number
] [
-.B -s
-.I config file name
+.B \-s
+.I configuration file
]
-
.SH DESCRIPTION
This program is part of the Samba suite.
@@ -51,44 +36,36 @@ 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.
+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).
+
+.B nmbd
+can also be used as a WINS (Windows Internet Name Server) server.
+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.
+Resolvable names include all names in the netbios hosts file (if any, see
+.B \-H
+below), its own name, and any other names that it may have learned about
+from other browsers on the network.
+A change to previous versions is that nmbd will now no longer
+do this automatically by default.
.SH OPTIONS
-.B -B
+.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.
+This option is obsolete. Please use the "interfaces" option in smb.conf instead.
.RE
-.B -I
+
+.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.
+This option is obsolete. Please use the "interfaces" option in smb.conf instead.
.RE
-.B -D
+.B \-D
.RS 3
If specified, this parameter causes the server to operate as a daemon. That is,
@@ -98,75 +75,60 @@ appropriate port.
By default, the server will NOT operate as a daemon.
.RE
-.B -C comment string
+.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".
+This option is obsolete. Please use the "server string" option in smb.conf
+instead.
.RE
-.B -G
+.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.
+This option is obsolete. Please use the "workgroup" option in smb.conf instead.
.RE
-.B -H
+.B \-H
+.I netbios hosts file
.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.
+netbios names for which the server should send a reply if queried.
+This option allows you to specify a file containing such a list.
+The syntax of the hosts file 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.
+gethostbyname() when read. An IP address of 0.0.0.0 will be
+interpreted as the server's 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.
+only flag supported is M, which means that this name is the default
+netbios name for this machine. This has the same effect as specifying the
+.B \-n
+option to
+.BR nmbd .
-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).
+NOTE: The G and S flags are now obsolete and are replaced by the
+"interfaces" and "remote announce" options in smb.conf.
-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.
+The default hosts file name is set at compile time, typically as
+.I /etc/lmhosts,
+but this may be changed in the Samba Makefile.
-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 for
+any name known to it. This includes all names in the netbios hosts file,
+its own name, and any other names it may have learned about from other
+browsers on the network.
-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.
+The primary intention of the
+.B \-H
+option is to allow a mapping from netbios names to internet domain names.
.B Example:
@@ -177,315 +139,118 @@ of groups that the server should be part of.
# 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
+.B \-N
.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.
-
+This option is obsolete. Please use the "interfaces" option in smb.conf instead.
.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
+.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.
+.RS 3
+This option sets the debug level. See
+.BR smb.conf (5).
.RE
-.B -l
+.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
+The
+.I log file
+parameter specifies a path and base filename into which operational data
+from the running
+.B nmbd
+server will be logged.
+The actual log file name is generated by appending the extension ".nmb" to
+the specified base name.
+For example, if the name specified was "log" then the file log.nmb would
+contain the debugging data.
+
+The default log file is specified at compile time, typically as
+.I /var/log/log.nmb.
.RE
-.B -n
+.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.
+This option allows you to override the Netbios name that Samba uses for itself.
.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
+.B \-a
.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"
-below.
+If this parameter is specified, the log files will be appended to with each
+new connection. This is the default.
.RE
-.B /etc/services
+.B \-o
.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.
+Overwrite existing log files instead of appending to them. (This was the
+default until version 2.0.0.)
.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:
+.B \-p
+.I port number
.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:
+port number is a positive integer value.
-.RS 3
-/usr/local/smb/nmbd -D -l/var/adm/smblogs/log
+Don't use this option unless you are an expert, in which case you
+won't need help!
.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:
+.B \-s
+.I configuration file
.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.
+The default configuration file name is set at compile time, typically as
+.I /etc/smb.conf,
+but this may be changed in the Samba Makefile.
-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
+The file specified contains the configuration details required by the server.
+See
+.BR smb.conf (5)
+for more information.
.RE
+.SH SIGNALS
-(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.
+In version 1.9.18 and above, nmbd will accept SIGHUP, which will cause it to dump out
+it's namelists into the file namelist.debug in the SAMBA/var/locks directory. This
+will also cause nmbd to dump out it's server database in the log.nmb file.
+Also new in version 1.9.18 and above is the ability to raise the debug log
+level of nmbd by sending it a SIGUSR1 (kill -USR1 <nmbd-pid>) and to lower
+the nmbd log level by sending it a SIGUSR2 (kill -USR2 <nmbd-pid>). This
+is to allow transient problems to be diagnosed, whilst still running at
+a normally low log level.
.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.
+
+This man page is (mostly) correct for version 1.9.16 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.
+.BR inetd (8),
+.BR smbd (8),
+.BR smb.conf (5),
+.BR smbclient (1),
+.BR testparm (1),
+.BR testprns (1)
.SH CREDITS
The original Samba software and related utilities were created by
-Andrew Tridgell (samba-bugs@anu.edu.au). Andrew is also the Keeper
+Andrew Tridgell (samba-bugs@samba.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.
-
-
-
-
-
diff --git a/docs/manpages/samba.7 b/docs/manpages/samba.7
index 0c81f736b6e..ab954d01bb3 100644
--- a/docs/manpages/samba.7
+++ b/docs/manpages/samba.7
@@ -1,15 +1,14 @@
-.TH SAMBA 7 29/3/95 Samba Samba
+.TH SAMBA 7 "19 Sep 1998" "samba 2.0.0-alpha6"
.SH NAME
-Samba \- a LanManager like fileserver for Unix
+Samba \- a LanManager like 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
+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
@@ -18,25 +17,37 @@ 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,
+The
+.BR smbd (8)
+daemon provides the file and print services to SMB clients,
such as Windows for Workgroups, Windows NT or LanManager. The
-configuration file for this daemon is described in smb.conf(5).
+configuration file for this daemon is described in
+.BR smb.conf (5).
-The nmbd(8) daemon provides Netbios nameserving and browsing
+The
+.BR 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
+The
+.BR 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
+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)
+The
+.BR testparm (1)
+utility allows you to test your
+.BR smb.conf (5)
configuration file.
-The smbstatus(1) utility allows you to tell who is currently using the
-smbd(8) server.
-
+The
+.BR smbstatus (1)
+utility allows you to tell who is currently using the
+.BR smbd (8)
+server.
.SH AVAILABILITY
The Samba software suite is licensed under the Gnu Public License. A
@@ -45,7 +56,7 @@ 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
+ftp from samba.anu.edu.au in the directory pub/samba/. It is
also available on several mirror sites worldwide.
You may also find useful information about Samba on the newsgroup
@@ -54,29 +65,26 @@ 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/
-
+of the Samba mailing list, at http://samba.anu.edu.au/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.
+contacted via e-mail at samba-bugs@samba.anu.edu.au.
-There have also been an enourmous number of contributors to Samba from
+There have also been an enormous 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.
-
+directly to samba-bugs@samba.anu.edu.au. Note, however, that due to the
+enormous 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):
@@ -147,6 +155,8 @@ Contributors to the project are (in alphabetical order by email address):
(kuku@acds.physik.rwth-aachen.de)
???
(lance@fox.com)
+ Leighton, Luke
+ (lkcl@pires.co.uk)
Lendecke, Volker
(lendecke@namu01.gwdg.de)
???
@@ -175,8 +185,10 @@ Contributors to the project are (in alphabetical order by email address):
(joergs@toppoint.de)
S{rkel{, Vesa
(vesku@rankki.kcl.fi)
+ Terpstra, John
+ (jht@aquasoft.com.au)
Tridgell, Andrew
- (samba-bugs@anu.edu.au)
+ (samba-bugs@samba.anu.edu.au)
Troyer, Dean
(troyer@saifr00.ateng.az.honeywell.com)
Wakelin, Ross
diff --git a/docs/manpages/smb.conf.5 b/docs/manpages/smb.conf.5
index 933d71ff0c3..5ad66c6be1d 100644
--- a/docs/manpages/smb.conf.5
+++ b/docs/manpages/smb.conf.5
@@ -1,4 +1,4 @@
-.TH SMB.CONF 5 11/10/94 smb.conf smb.conf
+.TH SMB.CONF 5 "19 Sep 1998" "smb.conf 2.0.0-alpha6"
.SH NAME
smb.conf \- configuration file for smbd
.SH SYNOPSIS
@@ -15,7 +15,6 @@ 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
@@ -35,8 +34,8 @@ 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.
+Any line ending in a \e 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
@@ -91,7 +90,6 @@ means access will be permitted as the default guest user (specified elsewhere):
read only = true
printable = true
public = true
-
.SH SPECIAL SECTIONS
.SS The [global] section
@@ -124,7 +122,7 @@ If no path was given, the path is set to the user's home directory.
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.
+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.
@@ -212,6 +210,13 @@ 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 ("|").
+
+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 detils.
+
+.RE
.SH PARAMETERS
Parameters define the specific attributes of services.
@@ -221,7 +226,7 @@ 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
+specified in a service 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.
@@ -237,7 +242,7 @@ 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
+there are some general substitutions which apply whenever they might be
relevant. These are:
%S = the name of the current service, if any
@@ -267,6 +272,16 @@ personality".
%M = the internet name of the client machine
+%N = the name of your NIS home directory server. This is obtained from
+your NIS auto.map entry. If you have not compiled Samba with -DAUTOMOUNT
+then this value will be the same as %L.
+
+%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".
+
+%R = the selected protocol level after protocol negotiation. As of
+Samba 1.9.18 it can be one of CORE, COREPLUS, LANMAN1, LANMAN2 or NT1.
+
%d = The process id of the current server process
%a = the architecture of the remote machine. Only some are recognised,
@@ -283,7 +298,7 @@ substitutions and other smb.conf options.
.SS NAME MANGLING
-Samba supports "name mangling" so that Dos and Windows clients can use
+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.
@@ -317,13 +332,25 @@ 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
+.SS COMPLETE LIST OF GLOBAL PARAMETERS
Here is a list of all global parameters. See the section of each
parameter for details. Note that some are synonyms.
+announce as
+
+announce version
+
auto services
+bind interfaces only
+
+browse list
+
+character set
+
+client code page
+
config file
deadtime
@@ -336,38 +363,84 @@ default service
dfree command
+dns proxy
+
+domain controller
+
+domain logons
+
+domain master
+
encrypt passwords
getwd cache
+hide files
+
+hide dot files
+
+homedir map
+
hosts equiv
include
+interfaces
+
keepalive
+lm announce
+
+lm interval
+
lock dir
load printers
+local master
+
lock directory
log file
log level
+logon drive
+
+logon home
+
+logon path
+
+logon script
+
lpq cache time
mangled stack
max log size
+max mux
+
max packet
+max ttl
+
max xmit
+max wins ttl
+
message command
+min wins ttl
+
+name resolve order
+
+netbios aliases
+
+netbios name
+
+nis homedir
+
null passwords
os level
@@ -386,10 +459,10 @@ preferred master
preload
-printing
-
printcap name
+printer driver file
+
protocol
read bmpx
@@ -400,6 +473,10 @@ read raw
read size
+remote announce
+
+remote browse sync
+
root
root dir
@@ -410,27 +487,51 @@ security
server string
+shared file entries
+
+shared mem size
+
+smb passwd file
+
smbrun
+socket address
+
socket options
status
strip dot
+syslog
+
+syslog only
+
time offset
+time server
+
+unix realname
+
+username level
+
username map
use rhosts
valid chars
+wins proxy
+
+wins server
+
+wins support
+
workgroup
write raw
-.SS COMPLETE LIST OF SERVICE PARAMETER
+.SS COMPLETE LIST OF SERVICE PARAMETERS
Here is a list of all service parameters. See the section of each
parameter for details. Note that some are synonyms.
@@ -459,14 +560,36 @@ comment
default case
+delete readonly
+
+delete veto files
+
deny hosts
directory
+directory mask
+
+directory mode
+
dont descend
+dos filetimes
+
+dos filetime resolution
+
exec
+fake directory create times
+
+fake oplocks
+
+follow symlinks
+
+force create mode
+
+force directory mode
+
force group
force user
@@ -515,10 +638,14 @@ max connections
min print space
+networkstation user login
+
only guest
only user
+oplocks
+
path
postexec
@@ -529,6 +656,12 @@ preserve case
print command
+printer driver
+
+printer driver location
+
+printing
+
print ok
printable
@@ -567,6 +700,10 @@ users
valid users
+veto files
+
+veto oplock files
+
volume
wide links
@@ -582,9 +719,9 @@ write list
.SS EXPLANATION OF EACH PARAMETER
.RS 3
-.SS admin users (G)
+.SS admin users (S)
-This is a list of users who will be granted administrative privilages
+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).
@@ -598,6 +735,35 @@ file permissions.
.B Example:
admin users = jason
+.SS announce as (G)
+
+This specifies what type of server nmbd will announce itself as in
+browse lists. By default this is set to Windows NT. The valid options
+are "NT", "Win95" or "WfW" meaining Windows NT, 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.
+
+.B Default:
+ announce as = NT
+
+.B Example
+ announce as = Win95
+
+.SS announce version (G)
+
+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.
+
+.B Default:
+ announce version = 4.2
+
+.B Example:
+ announce version = 2.0
+
.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
@@ -612,21 +778,21 @@ then the "load printers" option is easier.
.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.
+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
"allow hosts = 150.203.5.". The full syntax of the list is described in
the man page
-.B hosts_access(5).
+.BR 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
@@ -653,33 +819,21 @@ deny access from one particular host
Note that access still requires suitable user-level passwords.
-See testparm(1) for a way of testing your host access to see if it
+See
+.BR 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)
+ none (i.e., 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
+This option is deprecated and is only included for backward
+compatibility.
.SS available (S)
This parameter lets you 'turn off' a service. If 'available = no', then
@@ -690,6 +844,40 @@ ALL attempts to connect to the service will fail. Such failures are logged.
.B Example:
available = no
+
+.SS bind interfaces only (G)
+This global parameter (new for 1.9.18) allows the Samba admin to limit
+what interfaces on a machine will serve smb requests. If affects file service
+(smbd) and name service (nmbd) in slightly different ways.
+
+For name service it causes nmbd to bind to ports 137 and 138 on
+the interfaces listed in the 'interfaces' parameter. nmbd 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 nmbd will service name requests on all of these
+sockets. If "bind interfaces only" is set then nmbd 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 'interfaces' parameter list. As unicast
+packets are received on the other sockets it allows nmbd to
+refuse to serve names to machines that send packets that arrive
+through any interfaces not listed in the 'interfaces' list.
+IP Source address spoofing does defeat this simple check, however
+so it must not be used seriously as a security feature for nmbd.
+
+For file service it causes smbd to bind only to the interface
+list given in the 'interfaces' parameter. This restricts the
+networks that smbd will serve to packets coming in those interfaces.
+Note that you should not use this parameter for machines that
+are serving ppp or other intermittant or non-broadcast network
+interfaces as it will not cope with non-permanent interfaces.
+
+.B Default:
+ bind interfaces only = False
+
+.B Example:
+ bind interfaces only = True
+
.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.
@@ -699,14 +887,71 @@ shares in a net view and in the browse list.
.B Example:
browseable = No
+.SS browse list(G)
+This controls whether the smbd will serve a browse list to a client
+doing a NetServerEnum call. Normally set to true. You should never
+need to change this.
+
+.B Default:
+ browse list = Yes
+
+.SS case sensitive (G)
+See the discussion on NAME MANGLING.
.SS case sig names (G)
See "case sensitive"
+.SS character set (G)
+This allows a smbd to map incoming characters from a DOS 850 Code page
+to either a Western European (ISO8859-1) or Easter European (ISO8859-2)
+code page. Normally not set, meaning no filename translation is done.
+
+.B Default
+
+ character set =
+
+.B Example
+
+ character set = iso8859-1
+
+.SS client code page (G)
+Currently (Samba 1.9.17 and above) this may be set to one of two
+values, 850 or 437. It specifies the base DOS code page that the
+clients accessing Samba are using. To determine this, open a DOS
+command prompt and type the command "chcp". 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 co-operates with the "valid chars" parameter in
+determining what characters are valid in filenames and how
+capitalization is done. It has been added as a convenience for
+clients whose code page is either 437 or 850 so a convoluted
+"valid chars" string does not have to be determined. If you
+set both this parameter and the "valid chars" parameter the
+"client code page" parameter MUST be set before the "valid chars"
+in the smb.conf file. The "valid chars" string will then augment
+the character settings in the "client code page" parameter.
+
+If "client code page" is set to a value other than 850 or 437
+it will default to 850.
+
+See also : "valid chars".
+
+.B Default
+
+ client code page = 850
+
+.B Example
+
+ client code page = 437
+
.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.
+This is a text field that is seen next to a share when a client does a
+net view to list what shares are available.
+
+If you want to set the string that is displayed next to the machine
+name then see the server string command.
.B Default:
No comment string
@@ -726,11 +971,11 @@ 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
+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).
.B Example:
- config file = /usr/local/samba/smb.conf.%m
+ config file = /usr/local/samba/lib/smb.conf.%m
.SS copy (S)
This parameter allows you to 'clone' service entries. The specified
@@ -750,21 +995,38 @@ in the configuration file than the service doing the copying.
.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.
+When a file is created, the neccessary 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 *not* 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 "force create mode" parameter
+which is set to 000 by default.
-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.
+For Samba 1.9.17 and above this parameter no longer affects directory
+modes. See the parameter 'directory mode' for details.
+
+See also the "force create mode" parameter for forcing particular
+mode bits to be set on created files.
+See also the "directory mode" parameter for masking mode bits on created
+directories.
.B Default:
- create mask = 0755
+ create mask = 0744
.B Example:
create mask = 0775
.SS create mode (S)
See
.B create mask.
-.SS dead time (G)
+
+.SS deadtime (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
@@ -782,13 +1044,15 @@ for most systems.
A deadtime of zero indicates that no auto-disconnection should be performed.
.B Default:
- dead time = 0
+ deadtime = 0
.B Example:
- dead time = 15
+ deadtime = 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
+(logging level) to be specified in the
+.B 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.
@@ -815,7 +1079,7 @@ 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
+Also note that as 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.
@@ -831,6 +1095,19 @@ things.
path = /%S
+.SS delete readonly (S)
+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.
+
+.B Default:
+ delete readonly = No
+
+.B Example:
+ delete readonly = Yes
.SS deny hosts (S)
A synonym for this parameter is 'hosts deny'.
@@ -839,10 +1116,38 @@ 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)
+ none (i.e., no hosts specifically excluded)
.B Example:
deny hosts = 150.203.4. badhost.mynet.edu.au
+
+.SS delete veto files (S)
+
+This option is used when Samba is attempting to delete a directory
+that contains one or more vetoed directories (see the 'veto files' 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 (eg. .AppleDouble)
+
+Setting 'delete veto files = True' allows these directories to be
+transparently deleted when the parent directory is deleted (so long
+as the user has permissions to do so).
+
+.B Default:
+ delete veto files = False
+
+.B Example:
+ delete veto files = True
+
+See
+.B veto files
+
.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
@@ -870,24 +1175,112 @@ Note: Your script should NOT be setuid or setgid and should be owned by
and remaining space will be used.
.B Example:
- dfree command = /usr/local/smb/dfree
+ dfree command = /usr/local/samba/bin/dfree
Where the script dfree (which must be made executable) could be
- #!/bin/sh
- df $1 | tail -1 | awk '{print $2" "$4}'
+.nf
+ #!/bin/sh
+ df $1 | tail -1 | awk '{print $2" "$4}'
+.fi
or perhaps (on Sys V)
+.nf
#!/bin/sh
/usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
-
+.fi
Note that you may have to replace the command names with full
path names on some systems.
.SS directory (S)
See
.B path.
+
+.SS directory mask (S)
+A synonym for this parameter is 'directory mode'.
+
+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 neccessary 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 *not* 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 "force directory mode" parameter.
+This parameter is set to 000 by default (ie. no extra mode bits are added).
+
+See the "force directory mode" parameter to cause particular mode
+bits to always be set on created directories.
+
+See also the "create mode" parameter for masking mode bits on created
+files.
+
+.B Default:
+ directory mask = 0755
+
+.B Example:
+ directory mask = 0775
+
+.SS directory mode (S)
+See
+.B directory mask.
+
+.SS dns proxy (G)
+
+Specifies that nmbd should (as a WINS server), on finding that a NetBIOS
+name has not been registered, treat the NetBIOS name word-for-word as
+a DNS name.
+
+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.
+
+Note also that nmbd will block completely until the DNS name is resolved.
+This will result in temporary loss of browsing and WINS services.
+Enable this option only if you are certain that DNS resolution is fast,
+or you can live with the consequences of periodic pauses in nmbd service.
+
+.B Default:
+ dns proxy = yes
+
+.SS domain controller (G)
+
+A boolean that says whether Samba should be a domain controller or
+not. Set it to "yes" to be a domain controller.
+
+.B Default:
+ domain controller = no
+
+.SS domain logons (G)
+
+If set to true, the Samba server will serve Windows 95 domain logons
+for the workgroup it is in. For more details on setting up this feature
+see the file DOMAINS.txt in the Samba source documentation directory.
+
+.B Default:
+ domain logons = no
+
+.SS domain master (G)
+
+Enable WAN-wide browse list collation. Local master browsers on
+broadcast-isolated subnets will give samba their local browse lists, and
+ask 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.
+
+.B Default:
+ domain master = no
+
.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
@@ -895,26 +1288,176 @@ Linux) that are either not of interest to clients or are infinitely deep
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
+descend" entries. For example you may need "./proc" instead of just
"/proc". Experimentation is the best policy :-)
.B Default:
- none (ie., all directories are OK to descend)
+ none (i.e., all directories are OK to descend)
.B Example:
dont descend = /proc,/dev
+.SS dos filetimes (S)
+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
+smbd is acting on behalf of is not the file owner. Setting this option
+to True allows DOS semantics and smbd will change the file timstamp as
+DOS requires. This is a correct implementation of a previous compile-time
+options (UTIME_WORKAROUND) which was broken and is now removed.
+
+.B Default:
+ dos filetimes = False
+
+.B Example:
+ dos filetimes = True
+
+.SS dos filetime resolution (S)
+Under the DOS and Windows FAT filesystem, the finest granulatity 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 smbd.
+
+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.
+
+.B Default:
+ dos filetime resolution = False
+
+.B Example:
+ dos filetime resolution = True
+
.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.
+with the client. Note that Windows NT 4.0 SP3 and above will by default
+expect encrypted passwords unless a registry entry is changed. To use
+encrypted passwords in Samba see the file docs/ENCRYPTION.txt.
.SS exec (S)
This is an alias for preexec
+.SS fake directory create times (S)
+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 deleted
+in the directory. NMAKE therefore finds all object files in the
+object directory bar the last one built are out of date compared
+to the directory and rebuilds them. Enabling this option ensures
+directories always predate their contents and an NMAKE build will
+proceed as expected.
+
+.B Default:
+ fake directory create times = False
+
+.B Example:
+ fake directory create times = True
+
+.SS fake oplocks (S)
+
+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 "fake oplocks = yes" Samba will always grant oplock
+requests no matter how many clients are using the file.
+
+By enabling this option 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. Use this option
+carefully!
+
+It is generally much better to use the real oplock support except for
+physically read-only media such as CDROMs.
+
+This option is disabled by default.
+
+.SS follow symlinks (S)
+
+This parameter allows the Samba administrator to stop smbd 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 /etc/pasword in their home directory for instance.
+However it will slow filename lookups down slightly.
+
+This option is enabled (ie. smbd will follow symbolic links)
+by default.
+
+.SS force create mode (S)
+This parameter specifies a set of UNIX mode bit permissions that
+will *always* 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. The default for this parameter is (in octel)
+000. The modes in this parameter are bitwise 'OR'ed onto the
+file mode after the mask set in the "create mask" parameter
+is applied.
+
+See also the parameter "create mask" for details on masking mode
+bits on created files.
+
+.B Default:
+ force create mode = 000
+
+.B Example:
+ force create mode = 0755
+
+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'.
+
+.SS force directory mode (S)
+This parameter specifies a set of UNIX mode bit permissions that
+will *always* 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 octel)
+0000 which will not add any extra permission bits to a created
+directory. This operation is done after the mode mask in the parameter
+"directory mask" is applied.
+
+See also the parameter "directory mask" for details on masking mode
+bits on created directories.
+
+.B Default:
+ force directory mode = 000
+
+.B Example:
+ force directory mode = 0755
+
+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'.
.SS force group (S)
This specifies a group name that all connections to this service
@@ -943,6 +1486,21 @@ password. Once connected, all file operations will be performed as the
.B Example:
force user = auser
+.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 group (S)
+This is an alias for "force group" and is only kept for compatibility
+with old versions of Samba. It may be removed in future versions.
+
.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
@@ -953,8 +1511,9 @@ 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.
+as your guest user (perhaps by using the "su \-" command) and trying to
+print using
+.BR lpr .
Note that as of version 1.9 of Samba this option may be set
differently for each service.
@@ -964,16 +1523,6 @@ differently for each service.
.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.
@@ -999,6 +1548,62 @@ a dot appear as hidden files.
.B Example:
hide dot files = no
+
+
+.SS hide files(S)
+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 "hide dot files", "veto files" and "case sensitive"
+
+.B Default
+ No files or directories are hidden by this option (dot files are
+ hidden by default because of the "hide dot files" option).
+
+.B Example
+ hide files = /.*/DesktopFolderDB/TrashFor%m/resource.frk/
+
+The above example is based on files that the Macintosh client (DAVE)
+creates for internal use, and also still hides all files beginning with
+a dot.
+
+.SS homedir map (G)
+If "nis homedir" is true, 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:
+
+username server:/some/file/system
+
+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.
+
+NB: The -DNETGROUP option is required in the Makefile for option to work
+and on some architectures the line -lrpcsvc needs to be added to the
+LIBSM variable. This is required for Solaris 2, FreeBSD and HPUX.
+
+See also "nis homedir"
+
+.B Default:
+ homedir map = auto.home
+
+.B Example:
+ homedir map = amd.homedir
.SS hosts allow (S)
See
.B allow hosts.
@@ -1006,10 +1611,6 @@ See
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
@@ -1033,12 +1634,44 @@ or perhaps on a home network where you trust your wife and kids :-)
.B Example
hosts equiv = /etc/hosts.equiv
+.SS include (G)
+
+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 %u, %P and %S
+
+.SS interfaces (G)
+
+This option allows you to setup multiple network interfaces, so that
+Samba can properly handle browsing on all interfaces.
+
+The option takes a list of ip/netmask pairs. The netmask may either be
+a bitmask, or a bitlength.
+
+For example, the following line:
+
+interfaces = 192.168.2.10/24 192.168.3.10/24
+
+would configure two network interfaces with IP addresses 192.168.2.10
+and 192.168.3.10. The netmasks of both interfaces would be set to
+255.255.255.0.
+
+You could produce an equivalent result by using:
+
+interfaces = 192.168.2.10/255.255.255.0 192.168.3.10/255.255.255.0
+
+if you prefer that format.
+
+If this option is not set then Samba will attempt to find a primary
+interface, but won't attempt to configure more than one interface.
+
.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.
+A name starting with @ is interpreted as a UNIX group.
The current servicename is substituted for %S. This is useful in the
[homes] section.
@@ -1051,48 +1684,87 @@ See also "valid 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)
+.SS keepalive (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
+ keep alive = 300
.B Example:
keep alive = 60
+
+.SS lm announce (G)
+
+This parameter determines if Samba 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, 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 'lm interval'. 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
+'lm interval'.
+
+See also "lm interval".
+
+.B Default:
+ lm announce = auto
+
+.B Example:
+ lm announce = true
+
+.SS lm interval (G)
+
+If Samba is set to produce Lanman announce broadcasts needed
+by OS/2 clients (see the "lm announce" parameter) 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 "lm announce" parameter.
+
+See also "lm announce".
+
+.B Default:
+ lm interval = 60
+
+.B Example:
+ lm interval = 120
+
.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
+ load printers = yes
.B Example:
- load printers = yes
+ load printers = no
+
+.SS local master (G)
+This option allows the nmbd to become a local master browser on a
+subnet. If set to False then nmbd 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 become the local master browser on a subnet, just
+that the nmbd will participate in elections for local master browser.
+
+.B Default:
+ local master = yes
.SS lock directory (G)
-This options specifies the directory where lock files will be placed.
+This option 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
+ lock directory = /usr/local/samba/var/locks
+
.SS locking (S)
This controls whether or not locking will be performed by the server in
response to lock requests from the client.
@@ -1123,11 +1795,102 @@ 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
+ log file = /usr/local/samba/var/log.%m
.SS log level (G)
see "debug level"
+.SS logon drive (G)
+
+This parameter specifies the local path to which the home directory
+will be connected (see "logon home") and is only used by NT Workstations.
+
+.B Example:
+ logon drive = h:
+
+.SS logon home (G)
+
+This parameter specifies the home directory location when a Win95 or
+NT Workstation logs into a Samba PDC. It allows you to do "NET USE
+H: /HOME" from a command prompt, for example.
+
+.B
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine.
+
+.B Example:
+ logon home = "\\\\remote_smb_server\\%U"
+
+.B Default:
+ logon home = "\\\\%N\\%U"
+
+.SS logon path (G)
+
+This parameter specifies the home directory where roaming profiles
+(USER.DAT / USER.MAN files for Windows 95) are stored.
+
+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 "desktop", "start menu", "nethood" and
+"programs" folders, and their contents, are loaded and displayed
+on your Windows 95 client.
+
+The share and the path must be readable by the user for the preferences
+and directories to be loaded onto the Windows 95 client. The share
+must be writeable when the logs in for the first time, in order that
+the Windows 95 client can create the user.dat and other directories.
+
+Thereafter, the directories and any of contents can, if required,
+be made read-only. It is not adviseable that the USER.DAT file be made
+read-only - rename it to USER.MAN to achieve the desired effect
+(a MANdatory 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 \\\\%N\\HOMES\profile_path will cause problems).
+
+.B
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine.
+
+.B Default:
+ logon path = \\\\%N\\%U\\profile
+
+.B Example:
+ logon path = \\\\PROFILESERVER\\HOME_DIR\\%U\\PROFILE
+
+.SS logon script (G)
+
+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 path of /usr/local/samba/netlogon, and
+logon script = STARTUP.BAT, then file that will be downloaded is:
+
+.B /usr/local/samba/netlogon/STARTUP.BAT
+
+The contents of the batch file is entirely your choice. A suggested
+command would be to add NET TIME \\\\SERVER /SET /YES, to force every
+machine to synchronise clocks with the same time server. Another use
+would be to add NET USE U: \\\\SERVER\\UTILS for commonly used utilities,
+or NET USE Q: \\\\SERVER\\ISO9001_QA.
+
+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.
+
+.B
+This option takes the standard substitutions, allowing you to have
+separate logon scripts for each user or machine.
+
+.B Example:
+ logon script = scripts/%U.bat
+
.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.
@@ -1137,9 +1900,11 @@ 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.
+low priority won't be sent to the printer. See also the
+.B lppause
+command.
-If a %p is given then the printername is put in it's place. A %j is
+If a %p is given then the printername is put in its 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
@@ -1187,9 +1952,9 @@ 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.
+Currently six styles of printer status information are supported; BSD,
+SYSV, AIX, HPUX, QNX, LPRNG and PLP. 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
@@ -1197,7 +1962,7 @@ 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
+If a %p is given then the printername 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 lpq
@@ -1216,7 +1981,7 @@ 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
+If a %p is given then the printername is put in its 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
@@ -1235,11 +2000,11 @@ 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.
+Currently seven styles of printer control are supported; BSD, SYSV, AIX
+HPUX, QNX, LPRNG and PLP. 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
+If a %p is given then the printername is put in its 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
@@ -1269,7 +2034,7 @@ output file content is undefined.
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
+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
@@ -1286,17 +2051,23 @@ 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 mangle case (S)
+
+See the section on "NAME MANGLING"
+
.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
+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 .html for HTML files, whereas under DOS .htm is more commonly
used.
So to map 'html' to 'htm' you put:
@@ -1304,7 +2075,7 @@ So to map 'html' to 'htm' you put:
mangled map = (*.html *.htm)
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
+filenames on some CDROMS (only visible under some UNIXes). To do this
use a map of (*;1 *)
.B default:
@@ -1313,12 +2084,8 @@ use a map of (*;1 *)
.B Example:
mangled map = (*;1 *)
-.SS mangle case (S)
-
-See the section on "NAME MANGLING"
-
.SS mangled names (S)
-This controls whether non-DOS names under Unix should be mapped to
+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.
@@ -1332,7 +2099,7 @@ 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
+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.
@@ -1346,7 +2113,7 @@ 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 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).
@@ -1358,8 +2125,8 @@ 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
+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.
@@ -1379,33 +2146,6 @@ software. Use this option to set it to whatever you prefer.
.B Example:
mangling char = ^
-.SS max log size (G)
-
-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.
-
-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.
@@ -1415,7 +2155,7 @@ 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
+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).
@@ -1429,12 +2169,16 @@ be prepared for some surprises!
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
+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 'create mask' to be set such that owner
+execute bit is not masked out (ie. it must include 100). See the
+parameter "create mask" for details.
+
.B Default:
map archive = yes
@@ -1442,8 +2186,12 @@ This can be quite annoying for shared source code, documents, etc...
map archive = no
.SS map hidden (S)
-This controls whether DOS style hidden files should be mapped to Unix
-execute bits.
+This controls whether DOS style hidden files should be mapped to the
+UNIX world execute bit.
+
+Note that this requires the 'create mask' to be set such that the world
+execute bit is not masked out (ie. it must include 001).
+See the parameter "create mask" for details.
.B Default:
map hidden = no
@@ -1451,8 +2199,12 @@ execute bits.
.B Example:
map hidden = yes
.SS map system (S)
-This controls whether DOS style system files should be mapped to Unix
-execute bits.
+This controls whether DOS style system files should be mapped to the
+UNIX group execute bit.
+
+Note that this requires the 'create mask' to be set such that the group
+execute bit is not masked out (ie. it must include 010). See the parameter
+"create mask" for details.
.B Default:
map system = no
@@ -1474,23 +2226,89 @@ will be stored in the directory specified by the "lock directory" option.
.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.
+.SS max disk size (G)
+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.
-.B Default:
- only user = False
+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 "max disk size".
-.B Example:
- only user = True
+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 "max disk size" of 0 means no limit.
+
+.B Default:
+ max disk size = 0
+
+.B Example:
+ max disk size = 1000
+
+.SS max log size (G)
+
+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.
+
+A size of 0 means no limit.
+
+.B Default:
+ max log size = 5000
+
+.B Example:
+ max log size = 1000
+
+.SS max mux (G)
+
+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.
+
+.B Default:
+ max mux = 50
+
+.SS max packet (G)
+
+A synonym for this parameter is 'packet size'.
+
+.SS max ttl (G)
+
+This option tells nmbd what the default 'time to live' of NetBIOS
+names should be (in seconds) when nmbd is requesting a name using
+either a broadcast or from a WINS server. You should never need to
+change this parameter.
+
+.B Default:
+ max ttl = 14400
+
+.SS max wins ttl (G)
+
+This option tells nmbd when acting as a WINS server (wins support = true)
+what the maximum 'time to live' of NetBIOS names that nmbd will grant will
+be (in seconds). You should never need to change this parameter.
+The default is 3 days (259200 seconds).
+
+.B Default:
+ max wins ttl = 259200
+
+.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 message command (G)
@@ -1540,7 +2358,7 @@ 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 \\
+message command = csh -c 'csh < %s |& /usr/local/samba/bin/smbclient \e
-M %m; rm %s' &
this would execute the command as a script on the server, then give
@@ -1566,6 +2384,113 @@ kilobytes. The default is 0, which means no limit.
.B Example:
min print space = 2000
+.SS min wins ttl (G)
+
+This option tells nmbd when acting as a WINS server (wins support = true)
+what the minimum 'time to live' of NetBIOS names that nmbd will grant will
+be (in seconds). You should never need to change this parameter.
+The default is 6 hours (21600 seconds).
+
+.B Default:
+ min wins ttl = 21600
+
+.SS name resolve order (G)
+
+This option is used by the programs smbd, nmbd and smbclient to determine
+what naming services and in what order to resolve host names to IP addresses.
+This option is most useful in smbclient. The option takes a space separated
+string of different name resolution options. These are "lmhosts", "host",
+"wins" and "bcast". They cause names to be resolved as follows :
+
+lmhosts : Lookup an IP address in the Samba lmhosts file.
+host : Do a standard host name to IP address resolution, using the
+ system /etc/hosts, NIS, or DNS lookups. This method of name
+ resolution is operating system depended (for instance on Solaris
+ this may be controlled by the /etc/nsswitch.conf file).
+wins : Query a name with the IP address listed in the "wins server ="
+ parameter. If no WINS server has been specified this method will
+ be ignored.
+bcast : Do a broadcast on each of the known local interfaces listed in
+ the "interfaces =" parameter. This is the least reliable of the
+ name resolution methods as it depends on the target host being
+ on a locally connected subnet.
+
+The default order is lmhosts, host, wins, bcast and these name resolution
+methods will be attempted in this order.
+
+This option was first introduced in Samba 1.9.18p4.
+
+.B Default:
+ name resolve order = lmhosts host wins bcast
+
+.Example:
+ name resolve order = lmhosts bcast host
+
+This will cause the local lmhosts file to be examined first, followed
+by a broadcast attempt, followed by a normal system hostname lookup.
+
+.SS netbios aliases (G)
+
+This is a list of names that nmbd 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 'netbios name'.
+
+.B Example:
+ netbios aliases = TEST TEST1 TEST2
+
+.SS netbios name (G)
+
+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 'netbios aliases'.
+
+.B Example:
+ netbios name = MYNAME
+
+.SS nis homedir (G)
+Get the home share server from a NIS (or YP) 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, two network hops are required
+to access the home directory and this can be very slow especially with
+writing via Samba to an NFS mounted directory. 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 (or YP) map specified in "homedir map" and return the
+server listed there.
+
+.B Default:
+ nis homedir = false
+
+.B Example:
+ nis homedir = true
+
+.SS networkstation user login (G)
+This global parameter (new for 1.9.18p3) affects server level security.
+With this set (recommended) samba will do a full NetWkstaUserLogon to
+confirm that the client really should have login rights. This can cause
+problems with machines in trust relationships in which case you can
+disable it here, but be warned, we have heard that some NT machines
+will then allow anyone in with any password! Make sure you test it.
+
+.B Default:
+ networkstation user login = yes
+
+.B Example:
+ networkstation user login = no
+
.SS null passwords (G)
Allow or disallow access to accounts that have null passwords.
@@ -1575,6 +2500,46 @@ Allow or disallow access to accounts that have null passwords.
.B Example:
null passwords = yes
+.SS only guest (S)
+A synonym for this command is 'guest only'.
+
+.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 oplocks (S)
+This boolean option tells smbd whether to issue oplocks (opportunistic
+locks) to file open requests on this share. The oplock code was introduced in
+Samba 1.9.18 and can dramatically (approx 30% or more) improve the speed
+of access to files on Samba servers. It allows the clients to agressively
+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 Speed.txt in the Samba docs/ directory.
+
+Oplocks may be selectively turned off on certain files on a per share basis.
+See the 'veto oplock files' parameter.
+
+.B Default:
+ oplocks = True
+
+.B Example:
+ oplocks = False
+
+
.SS os level (G)
This integer value controls what level Samba advertises itself as for
browse elections. See BROWSING.txt for details.
@@ -1585,19 +2550,19 @@ 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
+This string controls 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
+This chat sequence is often quite site specific, depending 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,
+the old and new passwords respectively. It can also contain the
+standard macros \en \er \et and \es to give line-feed, carriage-return,
tab and space.
The string can also contain a * which matches any sequence of
@@ -1611,17 +2576,18 @@ 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*"
+ passwd chat = "*Enter OLD password*" %o\en "*Enter NEW password*" %n\en \e
+ "*Reenter NEW password*" %n\en "*Password changed*"
+
.B Default:
- passwd chat = *old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*
+ passwd chat = *old*password* %o\en *new*password* %n\en *new*password* %n\en *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
+compile time. Any occurrences of %u will be replaced with the user
name.
Also note that many passwd programs insist in "reasonable" passwords,
@@ -1636,7 +2602,7 @@ Workgroups) uppercase the password before sending it.
passwd program = /sbin/passwd %u
.SS password level (G)
-Some client/server conbinations have difficulty with mixed-case passwords.
+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!
@@ -1665,7 +2631,7 @@ you probably have a slow crypt() routine. Samba now comes with a fast
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
+passwords are significant. The includes.h file tries to select the
right length for your system.
.B Default:
@@ -1678,18 +2644,22 @@ right length for your system.
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.
+do all its 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
+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
/etc/hosts.
+Note that with Samba 1.9.18p4 and above the name of the password
+server is looked up using the parameter "name resolve order=" 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 "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
+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.
@@ -1706,6 +2676,11 @@ 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.
+If you are using a WindowsNT server as your password server then you
+will have to ensure that your users are able to login from the Samba
+server, as the network logon will appear to come from there rather
+than from the users workstation.
+
.SS path (S)
A synonym for this parameter is 'directory'.
@@ -1718,8 +2693,8 @@ 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
+Any occurrences of %u in the path will be replaced with the username
+that the client is connecting as. Any occurrences 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.
@@ -1747,7 +2722,7 @@ See also preexec
none (no command executed)
.B Example:
- postexec = echo \"%u disconnected from %S from %m (%I)\" >> /tmp/log
+ postexec = echo \e"%u disconnected from %S from %m (%I)\e" >> /tmp/log
.SS postscript (S)
This parameter forces a printer to interpret the print files as
@@ -1771,8 +2746,8 @@ 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' &
+preexec = csh -c 'echo \e"Welcome to %S!\e" | \e
+ /usr/local/samba/bin/smbclient -M %m -I %I' &
Of course, this could get annoying after a while :-)
@@ -1782,15 +2757,28 @@ See also postexec
none (no command executed)
.B Example:
- preexec = echo \"%u connected to %S from %m (%I)\" >> /tmp/log
+ preexec = echo \e"%u connected to %S from %m (%I)\e" >> /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.
+for its workgroup.
+If this is set to true, on startup, samba 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 domain master = yes, so that samba 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
+.B os level = nn
-It is on by default.
+.B Default:
+ preferred master = no
.SS preload
This is an alias for "auto services"
@@ -1823,7 +2811,7 @@ 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
+use %f instead. Any occurrences 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 -
@@ -1838,7 +2826,7 @@ 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"
+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.
@@ -1853,10 +2841,10 @@ 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
+ print command = lpr -r -P %p %s
.B Example:
- print command = /usr/local/samba/myprintscript %p %s
+ print command = /usr/local/samba/bin/myprintscript %p %s
.SS print ok (S)
See
.B printable.
@@ -1876,33 +2864,29 @@ parameter controls only non-printing access to the resource.
.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.
+On SystemV systems that use lpstat to list available printers you
+can use "printcap name = lpstat" to automatically obtain lists of
+available printers. This is the default for systems that define
+SYSV at compile time in Samba (this includes most SystemV based
+systems). If "printcap name" is set to lpstat on these systems then
+Samba will launch "lpstat -v" and attempt to parse the output to
+obtain a printer list.
A minimal printcap file would look something like this:
print1|My Printer 1
+.br
print2|My Printer 2
+.br
print3|My Printer 3
+.br
print4|My Printer 4
+.br
print5|My Printer 5
where the | separates aliases of a printer. The fact that the second
@@ -1917,6 +2901,7 @@ will assume the file is in AIX "qconfig" format if the string
.B Example:
printcap name = /etc/myprintcap
+
.SS printer (S)
A synonym for this parameter is 'printer name'.
@@ -1931,9 +2916,85 @@ for any printable service that does not have its own printer name specified.
.B Example:
printer name = laserwriter
+
+.SS printer driver (S)
+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 WindowsNT 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 "printer driver" option set and the client will give you a
+list of printer drivers. The appropriate strings are shown in a
+scrollbox after you have chosen the printer manufacturer.
+
+.B Example:
+ printer driver = HP LaserJet 4L
+
.SS printer name (S)
See
.B printer.
+
+.SS printer driver file (G)
+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 :
+
+SAMBA_INSTALL_DIRECTORY/lib/printers.def
+
+This file is created from Windows 95 'msprint.def' files found on the
+Windows 95 client system. For more details on setting up serving of
+printer drivers to Windows 95 clients, see the documentation file
+docs/PRINTER_DRIVER.txt.
+
+.B Default:
+ None (set in compile).
+
+.B Example:
+ printer driver file = /usr/local/samba/printers/drivers.def
+
+Related parameters.
+.B printer driver location
+
+.SS printer driver location (S)
+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
+
+\e\eMACHINE\ePRINTER$
+
+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 documentation file
+docs/PRINTER_DRIVER.txt.
+
+.B Default:
+ None
+
+.B Example:
+ printer driver location = \e\eMACHINE\ePRINTER$
+
+Related paramerers.
+.B printer driver file
+
+
+.SS printing (S)
+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 six printing styles are supported. They are "printing =
+bsd", "printing = sysv", "printing = hpux", "printing = aix",
+"printing = qnx" and "printing = plp".
+
+To see what the defaults are for the other print commands when using
+these three options use the "testparm" program.
+
+As of version 1.9.18 of Samba this option can be set on a per printer basis
+
.SS protocol (G)
The value of the parameter (a string) is the highest protocol level that will
be supported by the server.
@@ -1941,6 +3002,9 @@ 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.
+Normally this option should not be set as the automatic negotiation
+phase in the SMB protocol takes care of choosing the appropriate protocol.
+
.B Default:
protocol = NT1
@@ -2037,11 +3101,65 @@ pointless and will cause you to allocate memory unnecessarily.
.B Example:
read size = 8192
+.SS remote announce (G)
+
+This option allows you to setup nmbd 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:
+
+ remote announce = 192.168.2.255/SERVERS 192.168.4.255/STAFF
+
+the above line would cause nmbd 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 "workgroup" option 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.
+
+This option replaces similar functionality from the nmbd lmhosts file.
+
+.SS remote browse sync (G)
+
+This option allows you to setup nmbd to periodically request synchronisation
+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:
+
+ remote browse sync = 192.168.2.255 192.168.4.255
+
+the above line would cause nmbd to request the master browser on the
+specified subnets or addresses to synchronise 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 it's segment.
+
+
.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
+connect to \e\eserver\eshare1 then to \e\eserver\eshare2 it won't
automatically allow the client to request connection to the second
share as the same username as the first without a password.
@@ -2084,8 +3202,20 @@ The set of files that must be mirrored is operating system dependent.
.B Example:
root directory = /homes/smb
+.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 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 security (G)
-This option does affects how clients respond to Samba.
+This option 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
@@ -2097,8 +3227,8 @@ 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
+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
@@ -2123,8 +3253,7 @@ 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.
+It also sets what will appear in browse lists next to the machine name.
A %v will be replaced with the Samba version number.
@@ -2136,50 +3265,52 @@ A %h will be replaced with the hostname.
.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.
+.SS set directory (S)
+If 'set directory = no', then users of the service may not use the setdir
+command to change directory.
-You must get this path right for many services to work correctly.
+The setdir command is only implemented in the Digital Pathworks client. See the
+Pathworks documentation for details.
-.B Default: taken from Makefile
+.B Default:
+ set directory = no
.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.
+ set directory = yes
-.B Default:
- short preserve case = no
+.SS shared file entries (G)
+This parameter has been removed (as of Samba 1.9.18 and above). The new
+System V shared memory code prohibits the user from allocating the
+share hash bucket size directly.
-See the section on "NAME MANGLING" for a fuller discussion.
+.SS shared mem size (G)
+This parameter is only useful when Samba has been compiled with FAST_SHARE_MODES.
+It specifies the size of the shared memory (in bytes) to use between smbd
+processes. You should never change this parameter unless you have studied
+the source and know what you are doing. This parameter defaults to 1024
+multiplied by the setting of the maximum number of open files in the
+file local.h in the Samba source code. MAX_OPEN_FILES is normally set
+to 100, so this parameter defaults to 102400 bytes.
-.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.
+.B Default
+ shared mem size = 102400
-.SS root postexec (S)
+.SS smb passwd file (G)
+This option sets the path to the encrypted smbpasswd file. This is a *VERY
+DANGEROUS OPTION* if the smb.conf is user writable. By default the path
+to the smbpasswd file is compiled into Samba.
-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 smbrun (G)
+This sets the full path to the smbrun binary. This defaults to the
+value in the Makefile.
-.SS set directory (S)
-If 'set directory = no', then users of the service may not use the setdir
-command to change directory.
+You must get this path right for many services to work correctly.
-The setdir comand is only implemented in the Digital Pathworks client. See the
-Pathworks documentation for details.
.B Default:
- set directory = no
+taken from Makefile
.B Example:
- set directory = yes
+ smbrun = /usr/local/samba/bin/smbrun
.SS share modes (S)
@@ -2187,15 +3318,15 @@ 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
+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.
+Enabling this option gives full share compatibility but may cost a bit
+of processing time on the UNIX server. They are enabled by default.
.B Default:
share modes = yes
@@ -2203,6 +3334,27 @@ of processing time on the unix server. They are enabled by default.
.B Example:
share modes = no
+.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 socket address (G)
+
+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.
+
+.B Example:
+ socket address = 192.168.2.20
+
.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
@@ -2222,7 +3374,7 @@ 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).
+(samba-bugs@samba.anu.edu.au).
Any of the supported socket options may be combined in any way you
like, as long as your OS allows it.
@@ -2284,9 +3436,12 @@ completely. Use these options with caution!
.SS status (G)
This enables or disables logging of connections to a status file that
-smbstatus can read.
+.B smbstatus
+can read.
-With this disabled smbstatus won't be able to tell you what
+With this disabled
+.B smbstatus
+won't be able to tell you what
connections are active.
.B Default:
@@ -2295,15 +3450,6 @@ connections are active.
.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
@@ -2322,11 +3468,42 @@ so in the vast majority of cases "strict locking = no" is preferable.
.B Example:
strict locking = yes
+.SS strip dot (G)
+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.
+
+.B Default:
+ strip dot = no
+
+.B Example:
+ strip dot = yes
+
+.SS syslog (G)
+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 to LOG_NOTICE, debug level three maps onto LOG_INFO.
+The paramter sets the threshold for doing the mapping, all Samba
+debug messages above this threashold are mapped to syslog LOG_DEBUG
+messages.
+
+.B Default:
+
+ syslog = 1
+
+.SS syslog only (G)
+If this parameter is set then Samba debug messages are logged into
+the system syslog only, and not to the debug log files.
+
+.B Default:
+ syslog only = no
+
.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
+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 fsync() call to ensure the data is written to disk.
@@ -2348,6 +3525,27 @@ that have incorrect daylight saving time handling.
.B Example:
time offset = 60
+.SS time server (G)
+This parameter determines if nmbd advertises itself as a time server
+to Windows clients. The default is False.
+
+.B Default:
+ time server = False
+
+.B Example:
+ time server = True
+
+.SS unix realname (G)
+This boolean parameter when set causes samba to supply the real name field
+from the unix password file to the client. This is useful for setting up
+mail clients and WWW browsers on systems used by more than one person.
+
+.B Default:
+ unix realname = no
+
+.B Example:
+ unix realname = yes
+
.SS user (S)
See
.B username.
@@ -2357,10 +3555,10 @@ 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
+The username= 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
+users have different WfWg usernames to UNIX usernames. In both these
+cases you may also be better using the \e\eserver\eshare%user syntax
instead.
The username= line is not a great solution in many cases as it means Samba
@@ -2369,7 +3567,7 @@ 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
+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
@@ -2395,47 +3593,88 @@ on how this parameter determines access to the services.
username = fred
username = fred, mary, jack, jane, @users, @pcgroup
+.SS username level (G)
+
+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 behaviour changes. This
+parameter is a number that specifies the number of uppercase combinations
+to try whilst 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'.
+
+.B Default:
+ username level = 0
+
+.B Example:
+ username level = 5
+
.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
+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
+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
+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
+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
-For example to map from he name "admin" or "administrator" to the unix
+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
root = admin administrator
-Or to map anyone in the unix group "system" to the unix name "sys" you
+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
+You can map Windows usernames that have spaces in them by using double
+quotes around the name. For example:
+
+ tridge = "Andrew Tridgell"
+
+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.
+
+ !sys = mary fred
+ guest = *
+
+
+Note that the remapping is applied to all occurrences of
+usernames. Thus if you connect to "\e\eserver\efred" 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
+"\e\eserver\emary" and will need to supply a password suitable for
+"mary" not "fred". The only exception to this is the username passed
to the "password server" (if you have one). The password server will
receive whatever username the client supplies without modification.
@@ -2462,7 +3701,7 @@ 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
+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
@@ -2473,11 +3712,20 @@ valid chars = Z
valid chars = z:Z
valid chars = 0132:0172
-The last two examples above actually add two characters, and alters
+The last two examples above actually add two characters, and alter
the uppercase and lowercase mappings appropriately.
+Note that you MUST specify this parameter after the "client code page"
+parameter if you have both set. If "client code page" is set after
+the "valid chars" parameter the "valid chars" settings will be
+overwritten.
+
+See also the "client code page" parameter.
+
.B Default
+.br
Samba defaults to using a reasonable set of valid characters
+.br
for english systems
.B Example
@@ -2486,9 +3734,15 @@ the uppercase and lowercase mappings appropriately.
The above example allows filenames to have the swedish characters in
them.
+NOTE: It is actually quite difficult to correctly produce a "valid
+chars" line for a particular system. To automate the process
+tino@augsburg.net has written a package called "validchars" which will
+automatically produce a complete "valid chars" line for a given client
+system. Look in the examples subdirectory for this package.
+
.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.
+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
@@ -2505,15 +3759,76 @@ See also "invalid users"
.B Example
valid users = greg, @pcusers
+
+.SS veto files(S)
+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 not include the
+unix directory separator "/".
+
+Note that the case sensitivity option is applicable in vetoing files.
+
+One feature of the veto files parameter that it is important to be
+aware of, is that if a directory contains nothing but files that
+match the veto files parameter (which means that Windows/DOS clients
+cannot ever see them) is deleted, the veto files within that directory
+*are automatically deleted* along with it, if the user has UNIX permissions
+to do so.
+
+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 "hide files" and "case sensitive"
+
+.B Default
+ No files or directories are vetoed.
+
+.B Examples
+ Example 1.
+ Veto any files containing the word Security,
+ any ending in .tmp, and any directory containing the
+ word root.
+
+ veto files = /*Security*/*.tmp/*root*/
+
+ Example 2.
+ Veto the Apple specific files that a NetAtalk server
+ creates.
+
+ veto files = /.AppleDouble/.bin/.AppleDesktop/Network Trash Folder/
+
+.SS veto oplock files (S)
+This parameter is only valid when the 'oplocks' 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 'veto files' parameter.
+
+.B Default
+ No files are vetoed for oplock grants.
+
+.B Examples
+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 .SEM. 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 :
+
+ veto oplock files = /*.SEM/
+
.SS volume (S)
This allows you to override the volume label returned for a
-share. Useful for CDROMs whos installation programs insist on a
+share. Useful for CDROMs with installation programs that 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
+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.
@@ -2524,12 +3839,40 @@ only to areas that are outside the directory tree being exported.
.B Example:
wide links = no
+.SS wins proxy (G)
+
+This is a boolean that controls if nmbd will respond to broadcast name
+queries on behalf of other hosts. You may need to set this to no for
+some older clients.
+
+.B Default:
+ wins proxy = no
+.SS wins server (G)
+
+This specifies the DNS name (or IP address) of the WINS server that Samba
+should register with. If you have a WINS server on your network then you
+should set this to the WINS servers name.
+
+You should point this at your WINS server if you have a multi-subnetted
+network.
+.B Default:
+ wins server =
+
+.SS wins support (G)
+
+This boolean controls if the nmbd 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 nmbd to be your WINS server. Note that you
+should *NEVER* set this to true on more than one machine in your
+network.
+
+.B Default:
+ wins support = 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.
+queried by clients.
.B Default:
set in the Makefile
@@ -2537,11 +3880,6 @@ the same value.
.B Example:
workgroup = MYGROUP
-.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'.
@@ -2576,6 +3914,11 @@ See also the "read list" option
.B Example:
write list = admin, root, @staff
+.SS write ok (S)
+See
+.B writable
+and
+.B read only.
.SS write raw (G)
This parameter controls whether or not the server will support raw writes when
transferring data from clients.
@@ -2585,6 +3928,7 @@ transferring data from clients.
.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
@@ -2595,15 +3939,15 @@ 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
+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%username method of passing a username.
+includes the \e\eserver\eservice%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
+Step 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.
@@ -2614,7 +3958,7 @@ 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
+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
@@ -2623,8 +3967,6 @@ 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,
@@ -2641,7 +3983,7 @@ 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
+This man page is (mostly) correct for version 1.9.18 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
@@ -2653,27 +3995,25 @@ 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)
+.BR smbd (8),
+.BR smbclient (1),
+.BR nmbd (8),
+.BR testparm (1),
+.BR testprns (1),
+.BR lpq (1),
+.BR 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.
+smbd command line (see
+.BR smbd (8)).
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
@@ -2684,26 +4024,25 @@ 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)
+.B samba-bugs@samba.anu.edu.au (Andrew Tridgell)
.RS 3
-or to the mailing list
+or to the mailing list:
.RE
.B samba@listproc.anu.edu.au
.RE
-You may also like to subscribe to the announcement channel
+You may also like to subscribe to the announcement channel:
.RS 3
-samba-announce@listproc.anu.edu.au
+.B samba-announce@listproc.anu.edu.au
.RE
To subscribe to these lists send a message to
@@ -2714,6 +4053,6 @@ Errors or suggestions for improvements to the Samba man pages should be
mailed to:
.RS 3
-.B samba-bugs@anu.edu.au (Andrew Tridgell)
+.B samba-bugs@samba.anu.edu.au (Andrew Tridgell)
.RE
diff --git a/docs/manpages/smbclient.1 b/docs/manpages/smbclient.1
index 5590e01296e..e58e94607cd 100644
--- a/docs/manpages/smbclient.1
+++ b/docs/manpages/smbclient.1
@@ -1,4 +1,4 @@
-.TH SMBCLIENT 1 17/1/1995 smbclient smbclient
+.TH SMBCLIENT 1 "19 Sep 1998" "smbclient 2.0.0-alpha6"
.SH NAME
smbclient \- ftp-like Lan Manager client program
.SH SYNOPSIS
@@ -7,43 +7,54 @@ smbclient \- ftp-like Lan Manager client program
[
.B password
] [
-.B -A
+.B \-A
] [
-.B -E
+.B \-E
] [
-.B -L
+.B \-L
.I host
] [
-.B -M
+.B \-M
.I host
] [
-.B -I
+.B \-I
.I IP number
] [
-.B -N
+.B \-R
+.I name resolve order
] [
-.B -P
+.B \-N
] [
-.B -U
+.B \-P
+] [
+.B \-U
.I username
] [
-.B -d
+.B \-d
.I debuglevel
] [
-.B -l
+.B \-l
.I log basename
] [
-.B -n
+.B \-n
.I netbios name
] [
-.B -O
+.B \-W
+.I workgroup
+] [
+.B \-O
.I socket options
] [
-.B -p
+.B \-p
.I port number
-.B -T
+] [
+.B \-c
+.I command string
+] [
+.B \-T
.I tar options
-.B -D
+] [
+.B \-D
.I initial directory
]
.SH DESCRIPTION
@@ -54,17 +65,17 @@ 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
+.BR 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"
+.B "\e\eserver\eservice"
where
.B server
is the netbios name of the Lan Manager server offering the desired service and
@@ -73,12 +84,17 @@ 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"
+.B "\e\elanman\eprinter"
.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.
+
+With Samba 1.9.18p4 the server name is looked up according to the
+"name resolve order=" parameter in the smb.conf file, allowing an
+administrator to change the order and methods by which server names
+are looked up.
.RE
.B password
@@ -87,16 +103,16 @@ be the same as the hostname of the machine running the server.
password
is the password required to access the specified service on the
specified server. If supplied, the
-.B -N
+.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
+.B \-U
option (see below)) and
-.B -N
+.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
+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
@@ -106,7 +122,16 @@ rejected by these servers.
Be cautious about including passwords in scripts.
.RE
-.B -A
+.B \-R name resolve order
+
+.RS 3
+This parameter will override the default name resolution order of the
+server listed in the "name resolve order" parameter in smb.conf. This
+is useful to force name resolution to take place by a particular method.
+This command line parameter only exists in Samba 1.9.18p4 and above.
+.RE
+
+.B \-A
.RS 3
This parameter, if specified, causes the maximum debug level to be selected.
@@ -115,21 +140,23 @@ a security issue involved, as at the maximum debug level cleartext passwords
may be written to some log files.
.RE
-.B -L
+.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
+The
+.B \-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.
+will list the shares available on Microsoft's public server.
.RE
-.B -M
+.B \-M
.RS 3
This options allows you to send messages, using the "WinPopup"
@@ -143,22 +170,30 @@ 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:
+One useful trick is to cat the message through
+.BR 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
+You may also find the
+.B \-U
+and
+.B \-I
+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.
+See the message command section of
+.BR smb.conf (5)
+for a description of how to handle incoming WinPopup messages in Samba.
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
+.B \-E
.RS 3
This parameter, if specified, causes the client to write messages to the
@@ -168,7 +203,7 @@ By default, the client writes messages to standard output - typically the
user's tty.
.RE
-.B -I
+.B \-I
.I IP number
.RS 3
@@ -185,7 +220,7 @@ There is no default for this parameter. If not supplied, it will be determined
automatically by the client as described above.
.RE
-.B -N
+.B \-N
.RS 3
If specified, this parameter suppresses the normal password prompt from the
@@ -196,14 +231,16 @@ Unless a password is specified on the command line or this parameter is
specified, the client will request a password.
.RE
-.B -O
+.B \-O
.I socket options
-.RS 3
-
-See the socket options section of smb.conf(5) for details
+.RS 3
+See the socket options section of
+.BR smb.conf (5)
+for details.
.RE
-.B -P
+
+.B \-P
.RS 3
If specified, the service requested will be connected to as a printer service
@@ -213,7 +250,7 @@ will not be applicable for such a connection.
By default, services will be connected to as NON-printer services.
.RE
-.B -U
+.B \-U
.I username
.RS 3
@@ -237,21 +274,28 @@ If no
is supplied and neither environment variable exists the user name will
be empty.
+If the USER environment variable containts a '%' character, everything
+after that will be treated as a password. This allows you to set the
+environment variable to be
+.B USER=username%password
+so that a password is not passed on the command line (where it may
+be seen by the ps command).
+
If the service you are connecting to requires a password, it can be supplied
using the
-.B -U
+.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
+.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
+.B \-N
option (suppress password prompt) is assumed.
If you specify the password as a parameter AND as part of
@@ -269,10 +313,10 @@ rejected by these servers.
Be cautious about including passwords in scripts.
.RE
-.B -d
+.B \-d
.I debuglevel
-.RS 3
+.RS 3
debuglevel is an integer from 0 to 5.
The default value if this parameter is not specified is zero.
@@ -288,7 +332,7 @@ use only by developers and generate HUGE amounts of log data, most of which
is extremely cryptic.
.RE
-.B -l
+.B \-l
.I log basename
.RS 3
@@ -312,9 +356,8 @@ log.client.out (containing outbound transaction data)
The log files generated are never removed by the client.
.RE
-.RE
-.B -n
+.B \-n
.I netbios name
.RS 3
@@ -323,10 +366,18 @@ 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
+.B \-W
+.I workgroup
+
.RS 3
+Override what workgroup is used for the connection. This may be needed
+to connect to some servers.
+.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.
@@ -336,15 +387,28 @@ the server. The standard (well-known) port number for the server is 139,
hence the default.
This parameter is not normally specified.
+.RE
-.B -T
+.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:
+.RS 3
+where
+.I tar options
+consists of one or more of
+.BR c ,
+.BR x ,
+.BR I ,
+.BR X ,
+.BR b ,
+.BR g ,
+.BR N
+or
+.BR a ;
+used as:
.LP
smbclient
-.B "\\\\\\\\server\\\\share"
+.B "\e\eserver\eshare"
\-TcxIXbgNa
[
.IR blocksize
@@ -354,21 +418,30 @@ smbclient
]
.IR tarfile
[
-.IR filenames....
+.IR filenames ...
]
-.RS3
+.RS 3
.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.
+tape device or "\-" for standard output. (May be useful to set debugging
+low
+.RB ( -d0 ))
+to avoid corrupting your tar file if using "\-"). Mutually
+exclusive with the
+.B x
+flag.
.B x
-Extract (restore) a local tar file back to a share. Unless the -D
+Extract (restore) a local tar file back to a share. Unless the
+.B \-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.
+the share. Must be followed by the name of the tar file, device or "\-"
+for standard input. Mutually exclusive with the
+.B c
+flag. Restored files have theuir creation times (mtime) set to the date saved in
+the tar file. Directories currently do not get their creation dates restored
+properly.
.B I
Include files and directories. Is the default behaviour when
@@ -389,49 +462,89 @@ blocks.
.B g
Incremental. Only back up files that have the archive bit set. Useful
-only with the c flag.
+only with the
+.B 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.
+only with the
+.B 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.
+up. Useful with the
+.B g
+(and
+.BR c )
+flags.
.LP
+.B Long File Names
+
+smbclient'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, smbclient's tar option places all files
+in the archive with relative names, not absolute names.
+
+.B Filenames ...
+
+All file names can be given as DOS path names (with \e as the component
+separator) or as UNIX path names (with / as the component separator).
+
.B Examples
-smbclient \\\\mypc\\myshare "" -N -Tx backup.tar
+smbclient \e\emypc\emyshare "" -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
+smbclient \e\emypc\emyshare "" -N -TXx backup.tar users/docs
Restore everything except users/docs
-smbclient \\\\mypc\\myshare "" -N -Tc backup.tar users/docs
+smbclient \e\emypc\emyshare "" -N -Tc backup.tar users/docs
Create a tar file of the files beneath users/docs.
+smbclient \e\emypc\emyshare "" -N -tc backup.tar users\edocs
+
+Create the same tar file as above, but now use a DOS path name.
+
+smbclient \e\emypc\emyshare "" -N -Tc backup.tar \e*
+
+Create a tar file of all the files and directories in the share.
+.RE
.RE
-.B -D
+.B \-D
.I initial directory
-.RS3
-
+.RS 3
Change to initial directory before starting. Probably only of any use
-with the tar (\-T) option.
+with the tar
+.RB ( \-T )
+option.
+.RE
+.B \-c
+.I command string
-.RE
+.RS 3
+command string is a semicolon separated list of commands to be
+executed instead of prompting from stdin.
+.B \-N
+is implied by
+.BR \-c .
+This is particularly useful in scripts and for printing stdin to
+the server, e.g. \-c 'print \-'.
+.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,
+Once the client is running, the user is presented with a prompt, "smb: \e>".
+The backslash ("\e") 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
@@ -573,7 +686,9 @@ Copy the file called
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
+Note that all transfers in
+.B smbclient
+are binary. See also the
.B lowercase
command.
.RE
@@ -637,7 +752,7 @@ when using the
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.
+because lowercase filenames are the norm on UNIX systems.
.RE
.RE
@@ -747,8 +862,9 @@ operation - refer to the
.B recurse
and
.B mask
-commands for more information. Note that all transfers in smbclient are
-binary. See also the
+commands for more information. Note that all transfers in
+.B smbclient
+are binary. See also the
.B lowercase
command.
.RE
@@ -791,8 +907,9 @@ operation - refer to the
.B recurse
and
.B mask
-commands for more information. Note that all transfers in smbclient are
-binary.
+commands for more information. Note that all transfers in
+.B smbclient
+are binary.
.RE
.RE
@@ -866,7 +983,9 @@ Copy the file called
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
+Note that all transfers in
+.B smbclient
+are binary. See also the
.B lowercase
command.
.RE
@@ -927,17 +1046,16 @@ None.
Toggle directory recursion for the commands
.B mget
and
-.B mput
-.
+.BR 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
+directory (i.e., the directory they are copying
+.IR 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
+.B mask
command.
When recursion is toggled OFF, only files from the current working
@@ -990,11 +1108,13 @@ Remove the specified directory (user access privileges permitting)
.RE
.B Description:
.RS 3
-Performs a tar operation - see -T command line option above. Behaviour
+Performs a tar operation - see the
+.B \-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
+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.
.RE
.RE
@@ -1035,7 +1155,7 @@ on all files it backs up (implies read/write share).
.RS 3
.B Parameters
.RS 3
-.I <filename> <perm=[+|-]rsha>
+.I <filename> <perm=[+|\-]rsha>
.RE
.B Description
@@ -1047,14 +1167,13 @@ 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
+.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
@@ -1063,10 +1182,8 @@ 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
@@ -1074,12 +1191,12 @@ 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
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
+It is recommended that the client software be installed under the
+/usr/local/samba
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!
@@ -1088,8 +1205,11 @@ 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
+server. It is possible to run
+.B smbd
+(see
+.BR 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
@@ -1100,8 +1220,7 @@ 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)
-
+.BR smbd (8)
.SH DIAGNOSTICS
[This section under construction]
@@ -1118,16 +1237,14 @@ 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
+Andrew Tridgell (samba-bugs@samba.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
+.BR smb.conf (5)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbd.8 b/docs/manpages/smbd.8
index bae41b2c479..d87995e2375 100644
--- a/docs/manpages/smbd.8
+++ b/docs/manpages/smbd.8
@@ -1,46 +1,51 @@
-.TH SMBD 8 17/1/1995 smbd smbd
+.TH SMBD 8 "19 Sep 1998" "smbd 2.0.0-alpha6"
.SH NAME
smbd \- provide SMB (aka LanManager) services to clients
.SH SYNOPSIS
.B smbd
[
-.B -D
+.B \-D
] [
-.B -a
+.B \-a
] [
-.B -d
+.B \-o
+] [
+.B \-d
.I debuglevel
] [
-.B -l
+.B \-l
.I log file
] [
-.B -p
+.B \-p
.I port number
] [
-.B -O
+.B \-O
.I socket options
] [
-.B -s
+.B \-s
.I configuration file
]
.SH DESCRIPTION
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.
+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. These include MSCLIENT 3.0 for DOS, Windows for Workgroups,
+Windows 95, Windows NT, OS/2, DAVE for Macintosh, and smbfs for Linux.
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
+.BR 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
+.BR 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
@@ -48,11 +53,13 @@ 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.
-
+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 smbd killed and restarted.
.SH OPTIONS
-.B -D
+.B \-D
.RS 3
If specified, this parameter causes the server to operate as a daemon. That is,
@@ -62,18 +69,25 @@ appropriate port.
By default, the server will NOT operate as a daemon.
.RE
-.B -a
+.B \-a
+
+.RS 3
+If this parameter is specified, each new connection will append log messages
+to the log file. This is the default.
+.RE
+
+.B \-o
.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.
+If this parameter is specified, the log files will be overwritten when opened.
+By default, the log files will be appended to.
.RE
-.B -d
+.B \-d
.I debuglevel
.RS 3
-debuglevel is an integer from 0 to 5.
+debuglevel is an integer from 0 to 10.
The default value if this parameter is not specified is zero.
@@ -88,7 +102,7 @@ use only by developers and generate HUGE amounts of log data, most of which
is extremely cryptic.
.RE
-.B -l
+.B \-l
.I log file
.RS 3
@@ -113,14 +127,16 @@ log.out (containing outbound transaction data)
The log files generated are never removed by the server.
.RE
-.B -O
+.B \-O
.I socket options
.RS 3
-See the socket options section of smb.conf(5) for details
+See the socket options section of
+.BR smb.conf (5)
+for details
.RE
-.B -p
+.B \-p
.I port number
.RS 3
@@ -135,10 +151,14 @@ 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.
.RE
-.B -s
+.B \-s
.I configuration file
.RS 3
@@ -148,9 +168,9 @@ 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.
+.BR smb.conf (5)
+for more information.
.RE
-
.SH FILES
.B /etc/inetd.conf
@@ -179,23 +199,23 @@ 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
+.B /usr/local/samba/lib/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.
+.BR smb.conf (5)
+for more information.
.RE
-.RE
-
.SH LIMITATIONS
-On some systems smbd cannot change uid back to root after a setuid() call.
+On some systems
+.B 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
@@ -206,13 +226,12 @@ 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
+/usr/local/samba 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
@@ -220,7 +239,7 @@ 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
+this hole from being exploited. This security 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.
@@ -239,9 +258,10 @@ modified to suit your needs.
The remaining notes will assume the following:
.RS 3
-smbd (the server program) installed in /usr/local/smb
+.B smbd
+(the server program) installed in /usr/local/samba/bin
-smb.conf (the configuration file) installed in /usr/local/smb
+smb.conf (the configuration file) installed in /usr/local/samba/lib
log files stored in /var/adm/smblogs
.RE
@@ -255,9 +275,13 @@ 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
+To run the server as a daemon from the command line, simply put the
+.B \-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
+command line - the
+.B \-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
@@ -273,7 +297,7 @@ 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
+/usr/local/samba/bin/smbd -D -l /var/adm/smblogs/log -s /usr/local/samba/lib/smb.conf
.RE
(The above should appear in your initialisation script as a single line.
@@ -282,7 +306,9 @@ 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
+parameters except the desired debug level and
+.B \-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
@@ -294,8 +320,9 @@ 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).
+.B smbd
+- refer to the man page
+.BR 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.
@@ -313,11 +340,14 @@ 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)):
+.BR 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
+.\" turn off right adjustment
+.ad l
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd -d1
+-l/var/adm/smblogs/log -s/usr/local/samba/lib/smb.conf
+.ad
.RE
(The above should appear in /etc/inetd.conf as a single line. Depending on
@@ -355,27 +385,28 @@ 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".
+able to connect to the service "\e\efred\emary".
To properly test and experiment with the server, we recommend using the
smbclient program (see
-.B smbclient(1)).
+.BR 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
+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)
-
+.BR hosts_access (5),
+.BR inetd (8),
+.BR nmbd (8),
+.BR smb.conf (5),
+.BR smbclient (1),
+.BR testparm (1),
+.BR testprns (1)
+.BR rfc1001.txt
+.BR rfc1002.txt
.SH DIAGNOSTICS
[This section under construction]
@@ -393,15 +424,29 @@ 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 SIGNALS
+
+In version 1.9.18 and above the debug log level of smbd may be raised
+by sending it a SIGUSR1 (kill -USR1 <smbd-pid>) and lowered by sending
+it a SIGUSR2 (kill -USR2 <smbd-pid>). This is to allow transient problems
+to be diagnosed, whilst still running at a normally low log level.
+
+Note that as the signal handlers send a debug write, they are not
+re-entrant in smbd. This you should wait until smbd 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 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
+Andrew Tridgell (samba-bugs@samba.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
+.BR smb.conf (5)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbmnt.8 b/docs/manpages/smbmnt.8
new file mode 100644
index 00000000000..c9d7b61c35f
--- /dev/null
+++ b/docs/manpages/smbmnt.8
@@ -0,0 +1,96 @@
+.TH SMBMNT 8 "19 Sep 1998" "smbmnt 2.0.0-alpha6"
+.SH NAME
+smbmnt \- mount smb file system
+.SH SYNOPSIS
+.B smbmnt
+.B mount-point
+[
+.B -u
+.I uid
+] [
+.B -g
+.I gid
+] [
+.B -f
+.I file mode
+] [
+.B -d
+.I dir mode
+]
+
+.SH DESCRIPTION
+.B smbmnt
+is a helper application used by the
+.BI smbmount (8)
+program to do the actual mounting.
+.B smbmnt
+is meant to be installed setuid root so that normal users can mount
+their smb shares. It checks whether the user has write permissions
+on the mount point and then mounts the directory.
+
+The
+.B smbmnt
+program is normally invoked by a mount command to
+.BI smbmount ,
+and the command line arguments are passed directly to
+.B smbmnt.
+
+.SH OPTIONS
+.B -u
+.I uid,
+.B -g
+.I gid
+.RS 3
+A Lan Manager server does not tell us anything about the owner of a
+file, but Unix requires that each file have an owner and a group it belongs
+to. With
+.B -u
+and
+.B -g
+you can tell smbmount which id's it should assign to the files in the
+mounted directory.
+
+The defaults for these values are the current uid and gid.
+.RE
+
+.B -f
+.I file mode,
+.B -d
+.I dir mode
+.RS 3
+Like
+.B -u
+and
+.B -g,
+these options are also used to bridge differences in concepts between
+Lan Manager and Unix. Lan Manager does not know anything about file
+permissions, so
+.B smbmnt
+must be told which permissions it should assign to the mounted files
+and directories.
+
+The values must be given as octal numbers. The default values are taken
+from the current umask, where the file mode is the current umask,
+and the dir mode adds execute permissions where the file mode gives
+read permissions.
+
+Note that these permissions can differ from the rights the server
+gives to us. If you do not have write permissions on the server,
+you should choose a file mode that matches your actual permissions.
+This certainly cannot override the restrictions imposed by the server.
+
+In addition to specifying the file mode, the
+.B -f
+argument can be used to specify certain bug-fix workarounds.
+This allows bug fixes to be enabled on a per mount-point basis,
+rather than being compiled into the kernel.
+The required bug fixes are specified by prepending an (octal) value
+to the file mode.
+For information on the available bug workarounds, refer to the
+.B smbfs.txt
+file in the Linux kernel Documentation directory.
+.RE
+
+.SH SEE ALSO
+.B smbmount(8)
+
diff --git a/docs/manpages/smbmount.8 b/docs/manpages/smbmount.8
new file mode 100644
index 00000000000..30feaaf87b5
--- /dev/null
+++ b/docs/manpages/smbmount.8
@@ -0,0 +1,44 @@
+.TH SMBMOUNT 8 "19 Sep 1998" "smbmount 2.0.0-alpha6"
+.SH NAME
+smbmount \- mount smb file system
+.SH SYNOPSIS
+.B smbmount
+[
+.B options
+]
+
+.SH DESCRIPTION
+.B smbmount
+is a stripped-down version of the
+.BI smbclient (1)
+program used to mount smbfs shares. It implements only the mount command,
+which then calls the
+.BI smbmnt (8)
+program to do the actual mount.
+.B smbmount
+itself accepts most of the options that
+.B smbclient
+does. See the
+.BI smbclient (1)
+manpage for details.
+
+To mount an smb file system, I suggest using the option
+.B -c
+for smbmount to pass the mount command. For example, use
+
+smbmount "\\\\server\\tmp" -c 'mount /mnt -u 123 -g 456'
+
+to mount the tmp share of server on /mnt, giving it a local uid 123
+and a local gid 456.
+
+The arguments supplied to the mount command are passed directly to the
+.B smbmnt
+utility for processing.
+Refer to the
+.BI smbmnt (8)
+manpage for details.
+
+.SH SEE ALSO
+.BI smbmnt (8),
+.BI smbclient (1)
+
diff --git a/docs/manpages/smbpasswd.8 b/docs/manpages/smbpasswd.8
new file mode 100644
index 00000000000..79524f941b6
--- /dev/null
+++ b/docs/manpages/smbpasswd.8
@@ -0,0 +1,138 @@
+.TH SMBPASSWD 8 "19 Sep 1998" "smbpasswd 2.0.0-alpha6"
+.SH NAME
+smbpasswd \- change a users smb password in the smbpasswd file.
+.SH SYNOPSIS
+.B smbpasswd
+[
+.B \-a
+] [
+.B \-r
+remote_machine
+] [
+.B username
+]
+.SH DESCRIPTION
+
+This program is part of the Samba suite.
+
+.B smbpasswd
+allows a user to change their encrypted smb password which
+is stored in the smbpasswd file (usually kept in the
+.I private
+directory under the
+.I Samba
+directory hierarchy. Ordinary users can only run the command
+with no options. It 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.
+
+.B New for 1.9.18p4.
+smbpasswd will now allow a user to change their password
+on a Windows NT server. To use this add the
+.I \-r
+.I \<remote_machine\>
+paramter to the smbpasswd command. The machine name is looked
+up using the "name resolve order" parameter defined in the
+smb.conf [global] section. Note that when changing a Windows
+NT password for a domain user,
+.I \<remote machine\>
+must be the name of the Primary domain controller.
+
+To allow users to change their passwords from "NO PASSWORD"
+in the smbpasswd file to a valid password the administrator
+must set the following parameter in the [global] section of
+the smb.conf :
+
+null passwords = true
+
+This is
+.B NOT
+recommended as a general policy, it is recommended that
+new users be assigned a default password instead.
+
+The
+.I \-a
+and
+.I username
+options can only be used by a user running as root.
+
+.SH OPTIONS
+.I \-a
+
+.RS 3
+Specifies that the username following should be added to
+the
+.I 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
+.I smbpasswd
+file and it is treated like a regular change password
+command. Note that the user to be added
+.B must
+already exist in the system password file (usually /etc/passwd)
+else the request to add the user will fail.
+
+.RE
+.I username
+
+.RS 3
+You may only specify a username to the smbpasswd command
+if you are running as root. Only root should have the
+permission to modify other users smb passwords.
+
+.RE
+.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
+.B smbpasswd
+program be installed in the /usr/local/samba/bin directory. This should be
+a directory readable by all, writeable only by root. The program should be
+executable by all. The program
+.B must not
+be setuid root.
+
+.SH VERSION
+
+This man page is correct for version 1.9.18p4 of the Samba suite.
+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
+.BR smbd (8),
+.BR smb.conf (5)
+.SH
+.B BUGS
+
+.RE
+The
+.B smbpasswd
+command is only useful if
+.I Samba
+has been set up to use encrypted passwords. See the file
+.I ENCRYPTION.txt
+in the docs directory for details on how to do this.
+
+.SH CREDITS
+.RE
+The original Samba software and related utilities were created by
+Andrew Tridgell (samba-bugs@samba.anu.edu.au). Andrew is also the Keeper
+of the Source for this project. smbpasswd and the encrypted password
+file code was written by Jeremy Allison (samba-bugs@samba.anu.edu.au).
+
+This man page was written by Jeremy Allison. Bug reports to samba-bugs@samba.anu.edu.au.
+
+See
+.BR smb.conf (5)
+for a full list of contributors and details of how to
+submit bug reports, comments etc.
diff --git a/docs/manpages/smbrun.1 b/docs/manpages/smbrun.1
index 1608d3bb345..617445f9363 100644
--- a/docs/manpages/smbrun.1
+++ b/docs/manpages/smbrun.1
@@ -1,4 +1,4 @@
-.TH SMBRUN 1 17/1/1995 smbrun smbrun
+.TH SMBRUN 1 "19 Sep 1998" "smbrun 2.0.0-alpha6"
.SH NAME
smbrun \- interface program between smbd and external programs
.SH SYNOPSIS
@@ -12,7 +12,7 @@ is a very small 'glue' program, which runs shell commands for
the
.B smbd
daemon (see
-.B smbd(8)).
+.BR 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
@@ -30,14 +30,13 @@ 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
+program be installed under the /usr/local/samba 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
@@ -48,23 +47,28 @@ 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)
+.BR smbd (8),
+.BR smb.conf (8)
.SH DIAGNOSTICS
-If smbrun cannot be located or cannot be executed by
+If
+.B smbrun
+cannot be located or cannot be executed by
+.B smbd
+then appropriate messages will be found in the
.B smbd
-then appropriate messages will be found in the smbd logs. Other diagnostics are
+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
+Andrew Tridgell (samba-bugs@samba.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)
+This man page was written by Karl Auer. Bug reports to samba-bugs@samba.anu.edu.au.
See
-.B smb.conf(5) for a full list of contributors and details of how to
+.BR smb.conf (5)
+for a full list of contributors and details of how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbstatus.1 b/docs/manpages/smbstatus.1
index 76dc50cbb53..5eaaff67fc1 100644
--- a/docs/manpages/smbstatus.1
+++ b/docs/manpages/smbstatus.1
@@ -1,41 +1,74 @@
-.TH SMBSTATUS 1 17/1/1995 smbstatus smbstatus
+.TH SMBSTATUS 1 "19 Sep 1998" "smbstatus 2.0.0-alpha6"
.SH NAME
smbstatus \- report on current Samba connections
.SH SYNOPSIS
.B smbstatus
-[-d]
-[-s
+[
+.B \-b
+] [
+.B \-d
+] [
+.B \-L
+] [
+.B \-p
+] [
+.B \-S
+] [
+.B \-s
.I configuration file
+] [
+.b \-u
+.i username
]
.SH DESCRIPTION
This program is part of the Samba suite.
.B smbstatus
-is a very simple program to list the current Samba connections
+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.
+Just run the program and the output is self explanatory.
+.SH OPTIONS
+.B \-b
+gives brief output.
-Option
-.I -d
+.B \-d
gives verbose output.
-.I -p
-print a list of smbd processes and exit. Useful for scripting.
+.B \-L
+causes smbstatus to only list locks.
+.B \-p
+print a list of
+.B smbd
+processes and exit. Useful for scripting.
+
+.B \-S
+causes smbstatus to only list shares.
+
+.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.
+See
+.BR smb.conf (5)
+for more information.
+
+.B \-u
+.I username
+selects information relevant to .B username only.
+
+.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 smbstatus
-program be installed under the /usr/local hierarchy, in a directory readable
+program be installed under the /usr/local/samba 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
@@ -44,9 +77,10 @@ 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)
+.BR smb.conf (5),
+.BR smbd (8)
See
-.B smb.conf(5) for a full list of contributors and details on how to
+.BR smb.conf (5)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/smbtar.1 b/docs/manpages/smbtar.1
index 0f1c38c271f..8c6b5de53b2 100644
--- a/docs/manpages/smbtar.1
+++ b/docs/manpages/smbtar.1
@@ -1,45 +1,51 @@
-.TH SMBTAR 1 18/2/96 smbtar smbtar
+.TH SMBTAR 1 "19 Sep 1998" "smbtar 2.0.0-alpha6"
.SH NAME
smbtar \- shell script for backing up SMB shares directly to UNIX tape drive
.SH SYNOPSIS
.B smbtar
.B \-s
.I server
-.B [ \-p
+[
+.B \-p
.I password
-.B ]
-.B [ \-x
+] [
+.B \-x
.I service
-.B ]
-.B [ \-X ]
-.B [ \-d
+] [
+.B \-X
+] [
+.B \-d
.I directory
-.B ]
-.B [ \-u
+] [
+.B \-u
.I user
-.B ]
-.B [ \-t
+] [
+.B \-t
.I tape
-.B ]
-.B [ \-b
+] [
+.B \-b
.I blocksize
-.B ]
-.B [ \-N
+] [
+.B \-N
.I filename
-.B ]
-.B [ \-i ]
-.B [ \-r ]
-.B [ \-l ]
-.B [ \-v ]
+] [
+.B \-i
+] [
+.B \-r
+] [
+.B \-l
+.I log level
+] [
+.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.
-
+is a very small shell script on top of
+.BR smbclient ,
+which dumps SMB shares directly to tape.
.SH OPTIONS
.B \-s
.I server
@@ -92,13 +98,15 @@ The user id to connect as. Default: UNIX login name.
.RS 3
Tape device. May be regular file or tape device. Default: Tape environmental
variable; if not set, a file called
-.I tar.out.
+.IR tar.out .
.RE
.B \-b
.I blocksize
.RS 3
-Blocking factor. Defaults to 20. See tar(1) for a fuller explanation.
+Blocking factor. Defaults to 20. See
+.BR tar (1)
+for a fuller explanation.
.RE
.B \-N
@@ -120,48 +128,52 @@ Restore. Files are restored to the share from the tar file.
.RE
.B \-l
+.I log level
.RS 3
-Debug level. Corresponds to -d flag on smbclient(1).
+Log (debug) level. Corresponds to
+.B \-d
+flag of
+.BR smbclient (1).
.RE
-
.SH ENVIRONMENT VARIABLES
The TAPE variable specifies the default tape device to write to. May
-be overidden with the -t option.
-
+be overridden with the
+.B \-t
+option.
.SH BUGS
-The smbtar script has different options from ordinary tar and tar
-called from smbclient.
-
+The
+.B smbtar
+script has different options from ordinary tar and tar
+called from
+.BR 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.
-
+should work on file lists. smbtar works best with GNU tar and may
+not work well with other versions.
.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)
+.BR smbclient (8),
+.BR smb.conf (8)
.SH DIAGNOSTICS
See diagnostics for
.B smbclient
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
+Andrew Tridgell (samba-bugs@samba.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
+man page. The
+.B 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,
+.BR smb.conf (5)
+for a full list of contributors and details of how to submit bug reports,
comments etc.
diff --git a/docs/manpages/smbumount.8 b/docs/manpages/smbumount.8
new file mode 100644
index 00000000000..152b991895d
--- /dev/null
+++ b/docs/manpages/smbumount.8
@@ -0,0 +1,28 @@
+.TH SMBUMOUNT 8 "19 Sep 1998" "smbumount 2.0.0-alpha6"
+.SH NAME
+smbumount \- umount for normal users
+.SH SYNOPSIS
+.B smbumount
+.B mount-point
+
+.SH DESCRIPTION
+With this program, normal users can unmount smb-filesystems, provided
+that it is suid root.
+
+.B smbumount
+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
+.B mount-point
+.RS 3
+.B mount-point
+is the directory you want to unmount.
+
+.SH SEE ALSO
+.B smbmount(8)
diff --git a/docs/manpages/testparm.1 b/docs/manpages/testparm.1
index 4a0ffcbc489..3dfbf2e6ba3 100644
--- a/docs/manpages/testparm.1
+++ b/docs/manpages/testparm.1
@@ -1,4 +1,4 @@
-.TH TESTPARM 1 17/1/1995 testparm testparm
+.TH TESTPARM 1 "19 Sep 1998" "testparm 2.0.0-alpha6"
.SH NAME
testparm \- check an smbd configuration file for internal correctness
.SH SYNOPSIS
@@ -18,7 +18,9 @@ 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
+the configuration file with confidence that
+.B smbd
+will successfully
load the configuration file.
Note that this is NOT a guarantee that the services specified in the
@@ -56,18 +58,18 @@ parameter is supplied, or strange things may happen.
.SH FILES
.B smb.conf
.RS 3
-This is usually the name of the configuration file used by smbd.
+This is usually the name of the configuration file used by
+.BR 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
+program be installed under the /usr/local/samba 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
@@ -78,8 +80,8 @@ 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)
+.BR smb.conf (5),
+.BR 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
@@ -93,12 +95,15 @@ Other messages are self-explanatory.
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
+Andrew Tridgell (samba-bugs@samba.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)
+The
+.B testparm
+program and this man page were written by Karl Auer. Bug reports to
+samba-bugs@samba.anu.edu.au.
See
-.B samba(7) for a full list of contributors and details on how to
+.BR samba (7)
+for a full list of contributors and details on how to
submit bug reports, comments etc.
diff --git a/docs/manpages/testprns.1 b/docs/manpages/testprns.1
index f1c3d3ef020..7c22c8e28ff 100644
--- a/docs/manpages/testprns.1
+++ b/docs/manpages/testprns.1
@@ -1,4 +1,4 @@
-.TH TESTPRNS 1 17/1/1995 testprns testprns
+.TH TESTPRNS 1 "19 Sep 1998" "testprns 2.0.0-alpha6"
.SH NAME
testprns \- check printer name for validity with smbd
.SH SYNOPSIS
@@ -30,11 +30,12 @@ file, single printer names and sets of aliases separated by vertical bars
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
+.BR testprns .
+However, if
.B testprns
-however if
-.B testprns
-finds the printer then smbd should do as well.
-
+finds the printer then
+.B smbd
+should do so as well.
.RE
.I printcapname
@@ -52,18 +53,17 @@ will attempt to scan the printcap file specified at compile time
.B /etc/printcap
.RS 3
This is usually the default printcap file to scan. See
-.B printcap(5)).
+.BR 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
+program be installed under the /usr/local/samba 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
@@ -74,9 +74,9 @@ 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)
+.BR printcap (5),
+.BR smbd (8),
+.BR smbclient (1)
.SH DIAGNOSTICS
If a printer is found to be valid, the message "Printer name <printername> is
valid" will be displayed.
@@ -84,7 +84,9 @@ 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
+All messages that would normally be logged during operation of
+.B 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
@@ -96,12 +98,15 @@ Other messages are self-explanatory.
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
+Andrew Tridgell (samba-bugs@samba.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)
+The
+.B testprns
+program and this man page were written by Karl Auer. Bug reports to
+samba-bugs@samba.anu.edu.au.
See
-.B samba(7) for a full list of contributors and details of how to
+.BR samba (7)
+for a full list of contributors and details of how to
submit bug reports, comments etc.
diff --git a/docs/samba.lsm b/docs/samba.lsm
index 503ba1ec94b..36abbba769a 100644
--- a/docs/samba.lsm
+++ b/docs/samba.lsm
@@ -7,11 +7,11 @@ 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
+AuthorEmail = samba-bugs@samba.anu.edu.au
Maintainer = Andrew Tridgell
-MaintEmail = samba-bugs@anu.edu.au
-Site1 = nimbus.anu.edu.au
-Path1 = pub/tridge/samba/
+MaintEmail = samba-bugs@samba.anu.edu.au
+Site1 = samba.anu.edu.au
+Path1 = pub/samba/
File1 = samba-latest.tar.gz
FileSize1 = 200K
Required1 = Ansi-C compiler and a TCP/IP network.
diff --git a/docs/textdocs/Application_Serving.txt b/docs/textdocs/Application_Serving.txt
new file mode 100644
index 00000000000..a82d559f31e
--- /dev/null
+++ b/docs/textdocs/Application_Serving.txt
@@ -0,0 +1,59 @@
+!==
+!== Application_Serving.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributed: January 7, 1997
+Updated: March 24, 1998
+Contributor: John H Terpstra <samba-bugs@samba.anu.edu.au>
+ 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..3d09cf59bc5
--- /dev/null
+++ b/docs/textdocs/BROWSING-Config.txt
@@ -0,0 +1,218 @@
+!==
+!== BROWSING-Config.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Date: July 5, 1998
+Contributor: John H Terpstra <jht@samba.anu.edu.au>
+
+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..7fe2abadd41 100644
--- a/docs/textdocs/BROWSING.txt
+++ b/docs/textdocs/BROWSING.txt
@@ -1,60 +1,69 @@
+!==
+!== BROWSING.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Author/s: Many (Thanks to Luke, Jeremy, Andrew, etc.)
+Updated: July 5, 1998
+Status: Current - For VERY Advanced Users ONLY
+
+Summary: This describes how to configure Samba for improved browsing.
+=====================================================================
+
+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.
+
+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.
+
+=====================================================================
+
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 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.
+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].
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.
-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.
-
-Be very careful setting up your lmhosts file. An incorrectly setup
-lmhosts file can have disasterous results for your net!
-
-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
-
-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.
-
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 +71,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:
+
+a) your local master browsers will be unable to find a domain master
+ browser, as it will only be looking on the local subnet.
-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.
+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.
-When Samba is the master browser it will regularly contact the domain
-controller to synchronise browse lists.
+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..68dcf56ac8d 100644
--- a/docs/textdocs/BUGS.txt
+++ b/docs/textdocs/BUGS.txt
@@ -1,31 +1,34 @@
-This file describes how to report Samba bugs.
+!==
+!== BUGS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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-bugs@samba.anu.edu.au <<
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.anu.edu.au/samba/
GENERAL INFO
@@ -36,6 +39,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 +59,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 +69,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 +130,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/CVS_ACCESS.txt b/docs/textdocs/CVS_ACCESS.txt
new file mode 100644
index 00000000000..212d9a235a2
--- /dev/null
+++ b/docs/textdocs/CVS_ACCESS.txt
@@ -0,0 +1,124 @@
+!==
+!== CVS_ACCESS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Modified from the Web pages by Jeremy Allison.
+Date: 23 Dec 1997
+Status: Current
+
+How to get access to Samba source code via cvs.
+===============================================
+
+CVS Access to samba.anu.edu.au
+------------------------------
+
+The machine samba.anu.edu.au runs a publicly accessible CVS
+repository for access to the source code of several packages,
+including samba, rsync and jitterbug. This document describes
+how to get anonymous read-only access to this source code.
+
+Access via cvsweb
+-----------------
+
+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.
+
+Use the URL : http://samba.anu.edu.au/cgi-bin/cvsweb
+
+Access via cvs
+--------------
+
+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 uptodate via normal cvs commands. This is the
+preferred method of access if you are a developer and not
+just a casual browser.
+
+To download the latest cvs source code, point your
+browser at the URL :
+
+http://www.cyclic.com/
+
+and click on the 'How to get cvs' link. CVS is free
+software under the GNU GPL (as is Samba).
+
+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
+
+1. Install a recent copy of cvs. All you really need is a
+ copy of the cvs client binary.
+
+2. Run the command
+
+ cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot login
+
+When it asks you for a password type 'cvs' (not including
+the quotes).
+
+3. Run the command
+
+ cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot co samba
+
+This will create a directory called samba containing the
+latest samba source code. This currently corresponds to the
+1.9.18alpha development tree.
+
+4. Whenever you want to merge in the latest code changes use
+the following command from within the samba directory:
+
+ cvs update -d -P
+
+NOTE: If you instead want the latest source code for the
+1.9.17 stable tree then replace step 4 with the command:
+
+ cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot co -r BRANCH_1_9_17 samba
+
+Access to the NT DOMAIN Controller code
+---------------------------------------
+
+The Samba PDC code is being separately developed on a
+branch named BRANCH_NTDOM. To gain access to the latest
+source code (this changes daily) do the following:
+
+1). Log onto cvs
+
+ cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot login
+
+When it asks you for a password type 'cvs' (not including
+the quotes).
+
+2). Check out the BRANCH_NTDOM by typing :
+
+ cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot co -r BRANCH_NTDOM samba
+
+This will create a directory called samba containing the
+latest snapshot of the domain controller code.
+
+3). To keep this code up to date after it has been
+changed in the cvs repository, cd into the samba
+directory you created above and type :
+
+ cvs update -d -P
+
+How it's done.
+--------------
+
+If you are interested in how anonymous cvs access is set up and
+want to set it up on your own system then you might like to checkout
+the pserver source code using the the command :
+
+ cvs -d :pserver:cvs@samba.anu.edu.au:/cvsroot co pserver
+
+You really have to know what you are doing to do this. Please don't
+email samba-bugs with basic cvs or unix security questions.
+
+Reporting problems.
+-------------------
+
+If you have any problems with this system please email
+samba-bugs@samba.anu.edu.au.
diff --git a/docs/textdocs/DHCP-Server-Configuration.txt b/docs/textdocs/DHCP-Server-Configuration.txt
new file mode 100644
index 00000000000..8754d12f845
--- /dev/null
+++ b/docs/textdocs/DHCP-Server-Configuration.txt
@@ -0,0 +1,203 @@
+!==
+!== DHCP-Server-Configuration.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Subject: DHCP Server Configuration for SMB Clients
+Date: March 1, 1998
+Contributor: John H Terpstra <jht@samba.anu.edu.au>
+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. Red Hat Linux 5.0 is one operating system that
+comes supplied with the ISC DHCP Server. ISC DHCP is available from
+ ftp://ftp.isc.org/isc/dhcp
+
+Incorrect configuration of MS Windows clients (Windows95, Windows NT Server and
+Workstation) will lead to problems with browsing and with general network
+operation. Windows 95 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.
+
+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.
+
+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 NOT be done via DHCP and must be assigned when MS Windows
+networking is first installed. 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,
+
+Other assignments can be made from a DHCP server too, but the above cover the
+major needs.
+
+
+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;
+ option netbios-dd-server 172.16.0.1;
+ option netbios-node-type 8;
+}
+
+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;
+ option netbios-dd-server 172.16.0.1;
+ option netbios-node-type 8;
+ 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 th eISC 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..3fd0452c96d 100644
--- a/docs/textdocs/DIAGNOSIS.txt
+++ b/docs/textdocs/DIAGNOSIS.txt
@@ -1,5 +1,11 @@
-DIAGNOSING YOUR SAMBA SERVER
-============================
+!==
+!== DIAGNOSIS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Andrew Tridgell
+Updated: October 14, 1997
+
+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
@@ -11,7 +17,7 @@ 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
+samba-bugs@samba.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
@@ -23,10 +29,12 @@ 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.
+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 +44,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 1.9.16 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 +81,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
@@ -77,7 +103,7 @@ 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
+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".
@@ -86,16 +112,28 @@ If you get a "session request failed" then the server refused the
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.
+
+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 +141,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 +149,13 @@ 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.
+
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,29 +166,21 @@ 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
@@ -168,6 +198,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 +231,16 @@ 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)
+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
@@ -221,17 +258,24 @@ TEST 10:
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.anu.edu.au. To find out more about samba and how to
+subscribe to the mailing list check out the samba web page at
+ http://samba.anu.edu.au/samba
+Also look at the other docs in the Samba package!
diff --git a/docs/textdocs/DNIX.txt b/docs/textdocs/DNIX.txt
index 51005e6ec8c..8c9046db525 100644
--- a/docs/textdocs/DNIX.txt
+++ b/docs/textdocs/DNIX.txt
@@ -1,3 +1,6 @@
+!==
+!== DNIX.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
DNIX has a problem with seteuid() and setegid(). These routines are
needed for Samba to work correctly, but they were left out of the DNIX
C library for some reason.
diff --git a/docs/textdocs/DOMAIN.txt b/docs/textdocs/DOMAIN.txt
index 31e19675fae..1c5abc701b6 100644
--- a/docs/textdocs/DOMAIN.txt
+++ b/docs/textdocs/DOMAIN.txt
@@ -1,68 +1,372 @@
-Samba now supports domain logons and network logon scripts. The
-support is still experimental, but it seems to work.
+!==
+!== DOMAIN.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Samba Team
+Updated: June 27, 1997
-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.
+Subject: Network Logons and Roving Profiles
+===========================================================================
+
+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 (samba does not
+support this, but NT server and other systems based on NT server do).
+
+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.
+
+Issues related to the single-logon network model are discussed in this
+document. Samba supports domain logons, network logon scripts, and user
+profiles. 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 Windows NT-style SAM database with other systems. However this is
+only one way of having a shared user database: exactly the same effect can
+be achieved by having all servers in a domain share a distributed NIS or
+Kerberos authentication database.
+
+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, ie 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.
+
+Another thing commonly associated with single-logon domains is remote
+administration over the SMB protocol. Again, there is no reason why this
+cannot be implemented with an underlying username database which is
+different from the Windows NT SAM. Support for the Remote Administration
+Protocol is planned for a future release of Samba.
+
+The domain support works for WfWg, and Win95 clients and NT 4.0 and 3.51.
+Domain support is currently at an early experimental stage for NT 4.0 and
+NT 3.51. Support for Windows OS/2 clients is still being worked on and is
+still experimental.
+
+Support for profiles is confirmed as working for Win95, NT 4.0 and NT 3.51.
+It is possible to specify: the profile location; script file to be loaded
+on login; the user's home directory; and for NT a kick-off time could also
+now easily be supported.
+
+With NT Workstations, all this does not require the use or intervention of
+an NT 4.0 or NT 3.51 server: Samba can now replace the logon services
+provided by an NT server, to a limited and experimental degree (for example,
+running "User Manager for Domains" will not provide you with access to
+a domain created by a Samba Server).
+
+With Win95, the help of an NT server can be enlisted, both for profile storage
+and for user authentication. For details on user authentication, see
+security_level.txt. For details on profile storage, see below.
-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.
+the Samba server; make clients run a batch file when they logon to
+the network and download their preferences, desktop and start menu.
+
+
+Configuration Instructions: Network Logons
+==========================================
+
+To use domain logons and profiles you need to do the following:
+
-To use domain logons you need to do the following:
+1) Setup nmbd and smbd by configuring smb.conf so that Samba is
+ acting as the master browser. See <your OS>_INSTALL.txt and BROWSING.txt
+ for details.
-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) Setup a WINS server (see NetBIOS.txt) and configure all your clients
+ to use that WINS service.
-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.
+3) 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, and the CONFIG.POL file
+ (Note: for details on the CONFIG.POL file, how to use it, what it is,
+ refer to the Microsoft Windows NT Administration documentation.
+ The format of these files is not known, so you will need to use
+ Microsoft tools).
For example I have used:
[netlogon]
path = /data/dos/netlogon
writeable = no
- guest ok = yes
+ guest ok = no
+Note that it is important that this share is not writeable by ordinary
+users, in a secure environment: ordinary users should not be allowed
+to modify or add files that another user's computer would then download
+when they log in.
-3) in the [global] section of smb.conf set the following:
+4) 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
+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:
+used. You can make the batch files come from a subdirectory by using
+something 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.
+5) 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.
+6) 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.
+7) 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
+domain logons to work correctly. Share level security won't work
correctly.
+
+Configuration Instructions: Setting up Roaming User Profiles
+================================================================
+
+In the [global] section of smb.conf set the following (for example):
+
+ logon path = \\profileserver\profileshare\profilepath\%U\moreprofilepath
+
+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. Windows 95 appears to
+check that it can see the share and any subdirectories within that share
+specified by the logon path option, rather than just connecting straight
+away. It also attempts to create the components of the full path for
+you. If the creation of any component fails, or if it cannot see any
+component of the path, the profile creation / reading fails.
+
+[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.]
+
+
+Windows 95
+----------
+
+When a user first logs in on Windows 95, 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 case preserve = yes" and
+"case sensitive = no" in order to maintain capital letters in shortcuts
+in any of the profile folders.
+
+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.
+
+2) 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.
+
+3) 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.
+
+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.
+
+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.
+
+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'.
+
+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.
+
+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.
+
+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.
+
+
+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".
+
+
+1) instead of logging in under the [user, password, domain] dialog],
+ press escape.
+
+2) run the regedit.exe program, and look in:
+
+ HKEY_LOCAL_MACHINE\Windows\CurrentVersion\ProfileList
+
+ 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.
+
+ [Exit the registry editor].
+
+3) WARNING - 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).
+
+ 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.
+
+4) search for the user's .PWL password-cacheing file in the c:\windows
+ directory, and delete it.
+
+5) log off the windows 95 client.
+
+6) 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.
+
+
+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.
+
+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.
+
+
+Windows NT Workstation 4.0
+--------------------------
+
+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, in exactly the same way as it
+can for Win95. [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].
+
+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.
+
+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].
+
+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.
+
+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.
+
+[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].
+
+[lkcl 20aug97 - after samba digest correspondance, 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].
+
+[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].
+
+
+Windows NT Server
+-----------------
+
+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.
+
+
+
+Sharing Profiles between W95 and NT Workstation 4.0
+---------------------------------------------------
+
+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.
+
+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].
+
+If you have this set up correctly, you will find separate user.DAT and
+NTuser.DAT files in the same profile directory.
+
+[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].
+
diff --git a/docs/textdocs/DOMAIN_CONTROL.txt b/docs/textdocs/DOMAIN_CONTROL.txt
new file mode 100644
index 00000000000..4d778de60fd
--- /dev/null
+++ b/docs/textdocs/DOMAIN_CONTROL.txt
@@ -0,0 +1,121 @@
+!==
+!== DOMAIN_CONTROL.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Initial Release: August 22, 1996
+Contributor: John H Terpstra <samba-bugs@samba.anu.edu.au>
+ Copyright (C) 1996-1997 - John H Terpstra
+Updated: July 5, 1998
+Status: Current
+
+Subject: Windows NT Domain Control & Samba
+============================================================================
+
+****NOTE:****
+=============
+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.
+
+Microsoft Windows NT Domain Control is an extremely complex protocol.
+We have received countless requests to implement Domain Control in Samba.
+The 1.9.18 release of Samba contains experimental code to implement
+this. Please read the file docs/NTDOMAIN.txt for more information on this.
+============================================================================
+
+Windows NT Server can be installed as either a plain file and print server
+(WORKGROUP workstaion 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.
+However only those servers which have licenced Windows NT code in them can be
+a primary Domain Controller (eg Windows NT Server, Advanced Server for Unix.)
+
+To many people these terms can be confusing, so let's try to clear the air.
+
+Every Windows NT system (workstation or server) has a registry database.
+The registry contains entries that describe the initialisation 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.
+
+The registry files can be located on any Windows NT machine by opening a
+command prompt and typing:
+ dir %SystemRoot%\System32\config
+
+The environment variable %SystemRoot% value can be obtained by typing:
+ echo %SystemRoot%
+
+The active parts of the registry that you may want to be familiar with are
+the files called: default, system, software, sam and security.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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 (ie: to ensure that the service action a user has
+requested is permitted within the limits of that user's privileges).
+
+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.
+
+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. At most every domain will have
+ONE Primary Domain Controller (PDC). It is desirable that each domain will
+have at least one Backup Domain Controller (BDC).
+
+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.
+
+Samba can NOT at this time function as a Domain Controller for any of these
+security services, but like all other domain members can interact with the
+Windows NT security system for all access authentication.
+
+When Samba is configured with the 'security = server' option and the
+'password server = Your_Windows_NT_Server_Name' option, then it will
+redirect all access authentication to that server. This way you can
+use Windows NT to act as your password server with full support for
+Microsoft encrypted passwords.
+
+Note also, that since release of samba-1.9.18 we now support native encrypted
+passwords too. To enable encrypted password handling several things need to be
+done:
+ 1) In smb.conf [globals]:
+ encrypt passwords = yes
+ smbpasswd file = /path/smbpasswd
+the standard path is /usr/local/samba/private/smbpasswd but this may be
+platform specific.
+
+ 2) Use "smbpasswd -a" to add all users to the smbpasswd file.
+
+Above all read all the documentation for encrypted password support - you will
+need it!
diff --git a/docs/textdocs/ENCRYPTION.txt b/docs/textdocs/ENCRYPTION.txt
index 046b473e9a1..010446915ad 100644
--- a/docs/textdocs/ENCRYPTION.txt
+++ b/docs/textdocs/ENCRYPTION.txt
@@ -1,9 +1,16 @@
- LanManager / Samba Password Encryption.
- ---------------------------------------
+!==
+!== ENCRYPTION.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Jeremy Allison <samba-bugs@samba.anu.edu.au>
+Updated: March 19, 1998
+Note: Please refer to WinNT.txt also
-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.
+Subject: LanManager / Samba Password Encryption.
+============================================================================
+
+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.
This document describes how the SMB password encryption algorithm
works and what issues there are in choosing whether you want to use
@@ -13,15 +20,19 @@ and the "PROS and CONS" section.
How does it work ?
------------------
- LanManager encryption is somewhat similar to UNIX password
+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
+users password. This is created by taking the users 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*.
+Windows NT encryption is a higher quality mechanism, consisting
+of doing an MD4 hash on a Unicode version of the users password. This
+also produces a 16 byte hash value that is non-reversible.
+
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
@@ -31,7 +42,7 @@ 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
+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*.
@@ -39,6 +50,9 @@ 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.
+For Windows NT protocol levels the above calculation is done on
+both hashes of the users password and both responses are returned
+in the SMB call, giving two 24 byte values.
The Samba server then reproduces the above calculation, using it's own
stored value of the 16 byte hashed password (read from the smbpasswd
@@ -52,8 +66,8 @@ 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
+users 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.
IMPORTANT NOTE ABOUT SECURITY
@@ -63,10 +77,10 @@ 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
+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 users 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
@@ -108,17 +122,18 @@ ftp
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.
-
+Note that Windows NT 4.0 Service pack 3 changed the default for
+permissible authentication so that plaintext passwords are *never*
+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.
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.
+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 users
password given the UNIX hash of it) then a separate password file
@@ -162,14 +177,16 @@ chmod 600 smbpasswd.
The format of the smbpasswd file is
-username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Long name:user home dir:user shell
+username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: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.
+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.
When the password file is created all users have password entries
consisting of 32 'X' characters. By default this disallows any access
@@ -185,12 +202,21 @@ 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
+bob:100:NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: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).
+password (not recommended). In order for you to allow this the
+smbpasswd program must be able to connect to the smbd daemon as
+that user with no password. Enable this by adding the line :
+
+null passwords = true
+
+to the [global] section of the smb.conf file (this is why the
+above scenario is not recommended). Preferebly, allocate your
+users a default password to begin with, so you do not have
+to enable this on your server.
Note : This file should be protected very carefully. Anyone with
access to this file can (with enough knowledge of the protocols) gain
@@ -200,25 +226,31 @@ normal unix /etc/passwd file.
The smbpasswd Command.
----------------------
- The smbpasswd command maintains the 32 byte password field in
+The smbpasswd command maintains the two 32 byte password fields 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.
+Samba binary directory).
-Note that if you do not do this then the root user will have to set all
-users passwords.
+Note that as of Samba 1.9.18p4 this program MUST NOT BE INSTALLED
+setuid root (the new smbpasswd code enforces this restriction so
+it cannot be run this way by accident).
-To set up smbpasswd as setuid root, change to the Samba binary install
-directory and then type (as root) :
+smbpasswd now works in a client-server mode where it contacts
+the local smbd to change the users password on its behalf. This
+has enormous benefits - as follows.
-chown root smbpasswd
-chmod 4555 smbpasswd
+1). smbpasswd no longer has to be setuid root - an enourmous
+range of potential security problems is eliminated.
-If smbpasswd is installed as setuid root then you would use it as
-follows.
+2). smbpasswd 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 users password).
+
+To run smbpasswd as a normal user just type :
smbpasswd
-Old SMB password: <type old alue here - just hit return if there is NO PASSWORD>
+Old SMB password: <type old value here - or hit return if there was no old password >
New SMB Password: < type new value >
Repeat New SMB Password: < re-type new value >
@@ -238,15 +270,8 @@ 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
+For more details on using smbpasswd refer to the man page which
+will always be the definitive reference.
Setting up Samba to support LanManager Encryption.
--------------------------------------------------
@@ -255,27 +280,15 @@ 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.
+1) compile and install samba as usual
-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
+2) if 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
+3) 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
+4) 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:
@@ -300,34 +313,18 @@ 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
+tridge:148:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: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
+5) set the passwords for users using the smbpasswd command. For
example, as root you could do "smbpasswd tridge"
-8) try it out!
+6) 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.
-
+==============================================================================
+Footnote: Please refer to WinNT.txt also
diff --git a/docs/textdocs/Faxing.txt b/docs/textdocs/Faxing.txt
new file mode 100644
index 00000000000..cecd0fa1423
--- /dev/null
+++ b/docs/textdocs/Faxing.txt
@@ -0,0 +1,223 @@
+!==
+!== Faxing.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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..86e8d2f96dc
--- /dev/null
+++ b/docs/textdocs/GOTCHAS.txt
@@ -0,0 +1,71 @@
+!==
+!== GOTCHAS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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/HINTS.txt b/docs/textdocs/HINTS.txt
index 953650bdd3e..2dd6377aea7 100644
--- a/docs/textdocs/HINTS.txt
+++ b/docs/textdocs/HINTS.txt
@@ -1,3 +1,13 @@
+!==
+!== HINTS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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 +50,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.anu.edu.au/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/MIRRORS.txt b/docs/textdocs/MIRRORS.txt
new file mode 100755
index 00000000000..dc864f7c14b
--- /dev/null
+++ b/docs/textdocs/MIRRORS.txt
@@ -0,0 +1,6 @@
+!==
+!== MIRRORS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+
+For a list of web and ftp mirrors please see
+http://samba.anu.edu.au/samba/
diff --git a/docs/textdocs/Macintosh_Clients.txt b/docs/textdocs/Macintosh_Clients.txt
new file mode 100644
index 00000000000..2e34eeb55b2
--- /dev/null
+++ b/docs/textdocs/Macintosh_Clients.txt
@@ -0,0 +1,26 @@
+!==
+!== Macintosh_Clients.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+> 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/NTDOMAIN.txt b/docs/textdocs/NTDOMAIN.txt
new file mode 100644
index 00000000000..b22ef849f94
--- /dev/null
+++ b/docs/textdocs/NTDOMAIN.txt
@@ -0,0 +1,155 @@
+!==
+!== NTDOMAIN.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Luke Kenneth Casson Leighton (samba-bugs@samba.anu.edu.au)
+ Copyright (C) 1997 Luke Kenneth Casson Leighton
+Created: October 20, 1997
+Updated: October 29, 1997
+
+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.
+
+
+Domain Logons using latest cvs source
+=====================================
+
+1) compile samba with -DNTDOMAIN
+
+2) set up samba with encrypted passwords: see ENCRYPTION.txt (probably out
+ of date: you no longer need the DES libraries, but other than that,
+ ENCRYPTION.txt is current).
+
+ at this point, you ought to test that your samba server is accessible
+ correctly with encrypted passwords, before progressing with any of the
+ NT workstation-specific bits: it's up to you.
+
+3) [ for each workstation, add a line to smbpasswd with a username of MACHINE$
+ and a password of "machine". this process will be automated in further
+ releases. lkcl02nov97 - done, as of 1.9.18alpha11! added new options
+ "domain hosts allow/deny" too :-) ]
+
+4) if using NT server to log in, run the User Manager for Domains, and
+ add the capability to "Log in Locally" to the policies, which you would
+ have to do even if you were logging in to another NT PDC instead of a
+ Samba PDC.
+
+5) set up the following parameters in smb.conf
+
+; substitute your workgroup here
+ workgroup = SAMBA
+
+; DO NOT add the redundant "domain sid = " parameter as this has
+; been superseded by code that automatically generates a random
+; sid for you.
+; domain sid = redundant.
+
+; tells workstations to use SAMBA as its Primary Domain Controller.
+ domain logons = yes
+
+6) make sure samba is running before the next step is carried out. if
+ this is your first time, just for fun you might like to switch the
+ debug log level to about 10. the NT pipes produces some very pretty
+ output when decoding requests and generating responses, which would
+ be particularly useful to see in tcpdump at some point.
+
+7) In the NT Network Settings, change the domain to SAMBA. Do
+ not attempt to create an account using the other part of the dialog:
+ it will fail at present.
+
+ You should get a wonderful message saying "Welcome to the SAMBA Domain."
+
+ If you don't, then please first increase your debug log levels and also
+ get a tcpdump (or preferably NetMonitor) trace and examine it carefully.
+ You should see a NETLOGON, a SAMLOGON on UDP port 138. If you don't,
+ then you probably don't have "domain logons = yes" or there is some other
+ problem in resolving the NetBIOS name SAMBA<1c>.
+
+ On port 139, you should see a LSA_OPEN_POLICY, two LSA_QUERY_INFOs (one
+ for a domain SID of S-1-3... and another for S-1-5) and then an LSA_CLOSE
+ or two.
+
+ You may see a pipe connection to a wksta service being refused: this
+ is acceptable, we have found. You may also see a "Net Server Get Info"
+ being issued on the srvsvc pipe.
+
+ Assuming you got the Welcome message, go through the obligatory reboot...
+
+8) When pressing Ctrl-Alt-Delete, the NT login box should have three entries.
+ If there is a delay of about twenty seconds between pressing Ctrl-Alt-Delete
+ and the appearance of this login dialog, then there might be a problem:
+ at this stage the workstation is issuing an LSA_ENUMTRUSTEDDOMAIN request
+
+ The domain box should have two entries: the hostname and the SAMBA domain.
+ Any local accounts are under the hostname domain, from which you will be
+ able to shut down the machine etc. At present, we do not specify that
+ the NT user logging in is a member of any groups, so will have no
+ priveleges, including the ability to shut down the machine [lkcl02nov97 -
+ done, as of samba-1.9.18alpha3! see "domain admin/guest users" and
+ "domain groups" parameters].
+
+ Select the SAMBA domain, and type in a valid username and password for
+ which there is a valid entry in the samba server's smbpasswd LM/NT OWF
+ database. At present, the password is ignored, to allow access to the
+ domain, but *not* ignored for accesses to Samba's SMB services: that's
+ completely separate from the SAM Logon process. Even if you log in a
+ user to a domain, your users will still need to connect to Samba SMB
+ shares with valid username / passwords, for that share.
+
+ You should see an LSA_REQ_CHAL, followed by LSA_AUTH2, LSA_NET_SRV_PWSET,
+ and LSA_SAM_LOGON. The SAM Logon will be particularly large (the response
+ can be approximately 600 bytes) as it contains user info.
+
+ Also, there will probably be a "Net Server Get Info" and a "Net Share Enum"
+ amongst this lot. If the SAM Logon is successful, the dialog should
+ disappear, and a standard SMB connection established to download the
+ profile specified in the SAM Logon (if it was).
+
+ At this point, you _may_ encounter difficulties in creating a remote
+ profile, and the login may terminate (generating an LSA_SAM_LOGOFF). If
+ this occurs, then either find an existing profile on the samba server and
+ copy it into the location specified by the "logon path" smb.conf parameter
+ for the user logging in, or log in on the local machine, and use the
+ System | Profiles control panel to make a copy of the _local_ profile onto
+ the samba server. This process is described and documented in the NT
+ Help Files.
+
+9) Play around. Look at the Samba Server: see if it can be found in the
+ browse lists. Check that it is accessible; run some applications.
+ Generally stress things. Laugh a lot. Logout of the NT machine
+ (generating an LSA_SAM_LOGOFF) and log back in again. Try logging in
+ two users simultaneously. Try logging the same user in twice.
+ Make Samba fall over, and then send bug reports to us, with NTDOM: at
+ the start of the subject line, as "samba-bugs@samba.anu.edu.au".
+
+Your reports, testing, patches, criticism and encouragement will help us
+get this right.
+
diff --git a/docs/textdocs/NetBIOS.txt b/docs/textdocs/NetBIOS.txt
new file mode 100644
index 00000000000..5eeae469f25
--- /dev/null
+++ b/docs/textdocs/NetBIOS.txt
@@ -0,0 +1,155 @@
+!==
+!== NetBIOS.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: lkcl - samba-bugs@arvidsjaur.anu.edu.au
+ 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/OS2-Client-HOWTO.txt b/docs/textdocs/OS2-Client-HOWTO.txt
new file mode 100644
index 00000000000..920a7e2c278
--- /dev/null
+++ b/docs/textdocs/OS2-Client-HOWTO.txt
@@ -0,0 +1,64 @@
+!==
+!== OS2-Client-HOWTO.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+
+
+Q. How can I configure OS/2 Warp Connect or OS/2 Warp 4 as a client for Samba?
+
+A. A more complete answer to this question can be found on:
+ http://carol.wins.uva.nl/~leeuw/samba/warp.html
+
+ Basically, you need three components:
+
+ * The File and Print Client ('IBM Peer')
+ * TCP/IP ('Internet support')
+ * The "NetBIOS over TCP/IP" driver ('TCPBEUI')
+
+ 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.
+
+ 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.
+
+ 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.
+
+
+Q. How can I configure OS/2 Warp 3 (not Connect), OS/2 1.2, 1.3 or 2.x for
+ Samba?
+
+A. You can use the free Microsoft LAN Manager 2.2c Client for OS/2 from
+ ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/
+ See http://carol.wins.uva.nl/~leeuw/lanman.html 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
+
+ 20=setup.exe
+ 20=netwksta.sys
+ 20=netvdd.sys
+
+ 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/">
+ ftp://ftp.cdrom.com/pub/os2/network/ndis/</a> instead.
+
+
+Q. Are there any other issues when OS/2 (any version) is used as a client?
+
+A. 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
+ http://carol.wins.uva.nl/~leeuw/samba/fix.html
+ 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.
+
+
diff --git a/docs/textdocs/PRINTER_DRIVER.txt b/docs/textdocs/PRINTER_DRIVER.txt
new file mode 100644
index 00000000000..44c132277b1
--- /dev/null
+++ b/docs/textdocs/PRINTER_DRIVER.txt
@@ -0,0 +1,240 @@
+!==
+!== PRINTER_DRIVER.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+==========================================================================
+ 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/PROFILES.txt b/docs/textdocs/PROFILES.txt
new file mode 100644
index 00000000000..1ade3694fb5
--- /dev/null
+++ b/docs/textdocs/PROFILES.txt
@@ -0,0 +1,388 @@
+!==
+!== PROFILES.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributors: Bruce Cook <BC3-AU@bigfoot.com>
+ Copyright (C) 1998 Bruce Cook
+
+ John Terpstra <samba-bugs@samba.anu.edu.au>
+ 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.anu.edu.au>
+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-bugs@samba.anu.edu.au 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.anu.edu.au>
+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/PROJECTS b/docs/textdocs/PROJECTS
index cf903f2c6dd..07f82c74d94 100644
--- a/docs/textdocs/PROJECTS
+++ b/docs/textdocs/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.anu.edu.au
========================================================================
Documentation and FAQ
Docs and FAQ files for the Samba suite of software.
-Contact Karl.Auer@anu.edu.au
+Contact samba-bugs@samba.anu.edu.au 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/Passwords.txt b/docs/textdocs/Passwords.txt
index e06876fecae..34acac08ba1 100644
--- a/docs/textdocs/Passwords.txt
+++ b/docs/textdocs/Passwords.txt
@@ -1,5 +1,12 @@
-NOTE ABOUT PASSWORDS
-====================
+!==
+!== Passwords.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Unknown
+Date: Unknown
+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
@@ -33,7 +40,7 @@ only written and tested for AFS 3.3 and later.
SECURITY = SERVER
=================
-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..34175fb8dc7
--- /dev/null
+++ b/docs/textdocs/Printing.txt
@@ -0,0 +1,132 @@
+!==
+!== Printing.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Unknown <samba-bugs@samba.anu.edu.au>
+Date: Unknown
+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-bugs@samba.anu.edu.au
+
+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:
+ print command
+ lpq command
+ lprm command
+
+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.
+
+On my system I use the following settings:
+
+ print command = lpr -r -P%p %s
+ lpq command = lpq -P%p
+ lprm command = lprm -P%p %j
+
+The % bits are "macros" that get dynamically replaced with variables
+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.
+
+When I'm debugging printing problems I often replace these command
+with pointers to 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 = cp %s /tmp/tmp.print
+
+then you print a file and look at the /tmp/tmp.print file to see what
+is produced. Try printing this file with lpr. Does it work? If not
+then your problem with with your lpr system, not with Samba. Often
+people have problems with their /etc/printcap file or permissions on
+various print queues.
+
+Another common problem is that /dev/null is not world writeable. Yes,
+amazing as it may seem, some systems make /dev/null only writeable by
+root. Samba uses /dev/null as a place to discard output from external
+commands like the "print command" so if /dev/null is not writeable
+then nothing will work.
+
+Other really common problems:
+
+- lpr isn't in the search path when Samba tries to run it. Fix this by
+using the full path name in the "print command"
+
+- the user that the PC is trying to print as doesn't have permission
+to print. Fix your lpr system.
+
+- you get an extra blank page of output. Fix this in your lpr system,
+probably by editing /etc/printcap. It could also be caused by
+incorrect setting on your 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 will affect if a blank page is
+output.
+
+- you get raw postscript instead of nice graphics on the output. Fix
+this either by using a "print command" that cleans up the file before
+sending it to lpr or by using the "postscript" option in smb.conf.
+
+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.
+
+If the above debug tips don't help, then maybe you need to bring in
+the bug gun, system tracing. See Tracing.txt in this directory.
+
+=====================================================================
+From Caldera Inc., the following documentation has been contributed:
+
+
+8.6 Setting up a raw SAMBA printer.
+
+Note: this is not a guide on setting up SAMBA. It merely addresses creating a printer configuration that will allow the output of regular (i.e. not PostScript) Windows printer drivers to print through SAMBA.
+
+Regular Windows printer drivers can be used to print via SAMBA, but you must set up a raw printer entry in "/etc/printcap" to accomplish this. Also, a print command will need to be specified in "/etc/smb.conf" that forces binary printing.
+
+The best way to start is to use printtool under X to create a new entry specifically for this printer. All you really need for it to do is create the necessary directories and set the permissions correctly, so don't worry about setting up a filter for a specific printer. Filters are not going to be used at all for this entry.
+
+Next, go into "/etc" and edit the printcap entry you just created, changing it to look like this (if you named it something other than raw, the entry name and spool directory should be changed here to match):
+
+raw:\
+ :rw:sh: \
+ :lp=/dev/lp1: \
+ :sd=/var/spool/lpd/raw: \
+ :fx=flp:
+
+When this is done and saved, edit the section of the smb.conf file that applies to the printer. Make sure the name of the section (enclosed in brackets) matches the name of the raw printer you just set up, then go down a line or two and add this line:
+
+print command = lpr -b -P%p %s
+
+Save the file, change to "/etc/rc.d/init.d", and type the following commands
+to restart the necessary daemons:
+
+./lpd stop
+./lpd start
+./smb stop
+./smb start
+
+At this point you should be ready to use the various printer drivers on
+your Windows clients for printing.
+=============================================================================
+
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.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..f9979441da8
--- /dev/null
+++ b/docs/textdocs/Recent-FAQs.txt
@@ -0,0 +1,289 @@
+!==
+!== Recent-FAQs.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Samba-bugs@samba.anu.edu.au
+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..be11f9f42ef
--- /dev/null
+++ b/docs/textdocs/RoutedNetworks.txt
@@ -0,0 +1,67 @@
+!==
+!== RoutedNetworks.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+#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
+remote machines. \ No newline at end of file
diff --git a/docs/textdocs/SCO.txt b/docs/textdocs/SCO.txt
index 1b3801471f7..85d0451730b 100644
--- a/docs/textdocs/SCO.txt
+++ b/docs/textdocs/SCO.txt
@@ -1,4 +1,14 @@
-There is an annoying TCPIP bug in SCO Unix. This causes orruption when
+!==
+!== SCO.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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/SSLeay.txt b/docs/textdocs/SSLeay.txt
new file mode 100644
index 00000000000..05c4923b195
--- /dev/null
+++ b/docs/textdocs/SSLeay.txt
@@ -0,0 +1,392 @@
+!==
+!== SSLeay.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Christian Starkjohann <cs@obdev.at>
+Date: May 29, 1998
+Status:
+
+Subject: Compiling and using samba with SSL support
+============================================================================
+
+What is SSL and SSLeay?
+=======================
+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. It is available from
+
+ ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/
+
+The current version while these lines are written is 0.9.0. Encryption is
+plagued by legal problems of all kinds. For a discussion of these please
+read the documentation of SSLeay, which is available at
+
+ http://www.psy.uq.edu.au/~ftp/Crypto/
+
+To compile samba with SSL support, you must first compile and install SSLeay.
+SSLeay consists of a library (which can be linked to other applications like
+samba) and several utility programs needed for key generation, certification
+etc. SSLeay installs to /usr/local/ssl/ by default.
+
+
+Compiling samba with SSLeay
+===========================
+1. Get and install SSLeay. The rest of this documentation assumes that you
+ have installed it at the default location, which is /usr/local/ssl/.
+ I have used SSLeay 0.9.0, but samba will probably also work with other
+ versions (but not with versions older than 0.6).
+2. Modify the Makefile. At the end of the configurable section you can find
+ the SSL definitions. You can find them quickly by searching for SSL_ROOT.
+ Unremark the definitions and modify SSL_ROOT if necessary.
+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.
+
+
+Running samba with SSLeay
+=========================
+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 SSLeay
+###########################################################################
+
+The first thing you should do is to change your PATH environment variable to
+include the bin directory of SSLeay. E.g.:
+
+ PATH=$PATH:/usr/local/ssl/bin
+
+Then you should set up SSLeay's random number generator. The state of this
+random number generator is held in the file ".rnd" in your home directory. To
+set a reasonable random seed, you need random data. Create a random file with
+
+ cat >/tmp/rfile.txt
+
+Then type random keys on your keyboard for about one minute. Then type the
+EOF character (^D) to terminate input. You may also use your favorite editor
+to create the random file, of course. Now you can create a dummy key to
+initialize the random number generator:
+
+ ssleay genrsa -rand /tmp/rfile.txt > /dev/null
+ rm -f /tmp/rfile.txt
+
+Don't forget to delete the file /tmp/rfile.txt. It's more or less equivalent
+to your private key!
+
+
+How to create a keypair
+=======================
+This is done with 'genrsa' for RSA keys and 'gendsa' for DSA keys. For an RSA
+key with 512 bits which is written to the file "key.pem" type:
+
+ ssleay genrsa -des3 512 > 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 "512". You really
+should use a pass phrase.
+
+If you want to remove the pass phrase from a key use:
+
+ ssleay rsa -in key.pem -out newkey.pem
+
+And to add or change a pass phrase:
+
+ ssleay 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
+
+ ssleay 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"):
+
+ ssleay 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:
+
+ ssleay 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 `ssleay 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..3ef4d228d66 100644
--- a/docs/textdocs/Speed.txt
+++ b/docs/textdocs/Speed.txt
@@ -1,8 +1,14 @@
-This file tries to outline the ways to improve the speed of a Samba server.
+!==
+!== Speed.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Andrew Tridgell
+Date: January 1995
+Status: Current
-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 +36,47 @@ 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.
+
+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 +127,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 +161,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 +250,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 +302,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 +327,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..81f05e50dd9
--- /dev/null
+++ b/docs/textdocs/Speed2.txt
@@ -0,0 +1,60 @@
+!==
+!== Speed2.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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
index d71bdaf7b3e..e1bfaef50b4 100644
--- a/docs/textdocs/Support.txt
+++ b/docs/textdocs/Support.txt
@@ -1,55 +1,526 @@
+!==
+!== Support.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
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.
+This is a list of companies who are prepared to support Samba
+commercially. We do not do check any of this information for
+accuracy, we just report what companies say about themselves in
+the hope that it will be useful.
-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.
+Note that the organisations listed below will expect you to pay for
+The support that they offer. We have been told that several people
+assumed this was a list of kindly companies offering free commercial
+support!
+
+For free support use the Samba mailing list and the comp.protocols.smb
+newsgroup.
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.
+contact the address below. Please make sure to include a header line
+giving the region and country, eg CANBERRA - AUSTRALIA, and use a
+similar format to the existing entries.
+
+The Samba Team reserves the right not to add support providers.
+
+You can contact the maintainers at samba-bugs@samba.anu.edu.au
+
+The support list has now been re-arranged into geographical areas
+and are sorted by state/region/town within these areas.
+These are currently:
+
+Region Number of entries
+----------------------------------------------------
+ AFRICA 2
+ AMERICA - CENTRAL & SOUTH 4
+ AMERICA - USA 38
+ ASIA 1
+ AUSTRALIA & NEW ZEALAND 20
+ CANADA 10
+ EUROPE 41
+ MIDDLE EAST 1
+
+AFRICA
+======
+
+------------------------------------------------------------------------------
+GAUTENG - SOUTH AFRICA
-You can contact the maintainers at samba-bugs@anu.edu.au
+Company: Obsidian Systems
+Street Addr: Boskruin Office Park Unit 3, Bosbok street, Randpark Ridge
+ Gauteng, 2156, South Africa.
+Postal Addr: PO Box 4938, Cresta, South Africa, 2118
+Contact no's: +2711 792-6500/38, Fax: +2711-792-6522
+ Cell: +2783-379-6889/90/91 or +2783-377-4946 or +27832660199
+Our level of experience: Low level programming and support for all samba
+security and compatability issues. We use Samba in South African Schools
+and commercial companies as an affordable solution for LAN and WAN
+networking.
+For futher information, please consult our website www.obsidian.co.za
------------------------------------------------------------------------------
-BRISBANE - AUSTRALIA
-Brett Worth
-Select Computer Technology - Brisbane
-431 Logan Road
-Stones Corner QLD 4120
-E-Mail: brett@sct.com.au
------------------------------------------------------------------------------
+JOHANNESBURG - SOUTH AFRICA
+
+ Company: Symphony Research (Pty) Ltd
+ Contact: Dr Evan Summers, <evan@sr.co.za>, tel 011 728-5742.
+keywords: Samba on Linux, support and consulting
+ Johannesburg (South Africa)
------------------------------------------------------------------------------
-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.
+
+
+
+
+
+
+AMERICA - CENTRAL & SOUTH
+=========================
+
+
+------------------------------------------------------------------------------
+ARGENTINA - SOUTH AMERICA
+
+Buenos Aires - Argentina
+
+Guillermo Sansovic
+Email: gui@usa.net
+Arkham Software
+Rivadavia 923 Piso 8
+1002 Buenos Aires
+Argentina
+
+Tel: + 54 1 345-0645
+
+At Arkham Software we have been working with Unix systems since 1986. We do
+intranets, software development and system integration. Our experience ith
+Samba dates from 1995.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-READING - ENGLAND
+CHILE - SOUTH AMERICA
+
+Company: Magic Consulting Group/Magic Dealer
+Street Addr: Alberto Reyes #035 Barrio Bellavista
+ Providencia Santiago
+Contact no's: +56 2 365 19 18, Fax: +56 2 365 14 55
+
+Contact Person: Marcelo Bartsch or Roy Zderich
+
+Email contact:
+Samba Support : samba@mg.dyn.ml.org
+Other NET OS Support : othernetos@mg.dyn.ml.org
+Other Questions : networks@mg.dyn.ml.org
+General Info: info@mg.dyn.ml.org
+
+Our level of experience: support for all Samba and Linux security and
+compatability issues. We use Samba in our local network and we have
+experience instaling it on some other locations. we also provide
+techincal support for Linux, Novell, Windows NT, OS/2 and other
+Operating Systems.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+HONDURAS - CENTRAL AMERICA
+
+Open Systems, S.A.
+
+Open Systems, S.A. provides support to SAMBA in SCO UnixWare 2.X:
+
+Server Platform: SCO UnixWare 2.X
+Client Platform: Windows NT, Windows 95, WFW (3.11), DOS.
+
+Open Systems, S.A. also provides consulting services and technical
+support in the following server platforms since 1987:
+
+SCO Open Server 3.0 and 5.0
+SCO UnixWare 2.X (SVR4.2MP)
+UNIX SVR4 (NCR, UNISYS)
+
+Contact:
+Selim Jose Miselem
+Open Systems, S.A.
+Centro Comercial Dallas
+San Pedro Sula, Honduras, Central America
+Tel/Fax 011 (504) 529868
+e-mail: selim@opensys.hn
+URL: http://www.opensys.hn
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+VILLAHERMOSA, TAB. - MEXICO
+
+Carlos Enrique García Díaz
+E-mail: cgarcia@tnet.net.mx
+Phone: (93) 12-33-91
+
+Samba experience:
+Server: Samba 1.9.15 and above with Solaris (Sparc & x86), SG Irix 5.2 - 6.3,
+AIX 3.2, DEC OSF1 v4.0, DG/UX v4.11, SunOS.
+Client: WinNT, Win95, WfWg, Win 3.1 & LAN WorkPlace.
+------------------------------------------------------------------------------
+
+
+
+
+
+
+
+AMERICA - USA
+=============
+
+------------------------------------------------------------------------------
+ARIZONA - USA
+
+Stephen Greenberg
+Nick Temple
+Coactiv Systems Inc.
+4625 S. Lakeshore Drive, suite 401
+Tempe, AZ 85282
+(602) 345 4114
+(602) 345 4105 fax
+steveg@coactiv.net
+
+We are LAN/WAN integrators who specialize in the standard fare (i.e. Novell
+and NT) as well as UNIX, NTRIGUE and SAMBA.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BAY AREA, SILICON VALLEY CALIFORNIA - USA
+
+Adital Corp.
+
+7291 Coronado Dr. ,Suite 4 San-Jose Ca 95129
+
+Phone : (408) 257-7717 Fax : (408) 257-7772 E-Mail: ephi@adital.com
+
+Contact: Ephi Dror, Director of software development.
+
+Adital is a company that specialized in networking products development.
+We have been doing many development projects on Windows (NT/95), Macintosh,
+UNIX and embedded system platforms in the area of networking drivers and
+applications during the last few years. In regards to SAMBA, we have a lot
+of experience in SMB/CIFS protocol development.
+
+We have special expertise in porting SAMBA to embedded system environments for
+NT/WIN95/WFW client/server connectivity.
+
+We can help you defining and specifying your product as well as designing,
+implementing, testing, upgrading and maintaining it.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SAN FRANCISCO BAY AREA - USA
+
+Alex Davis --- President of FTL
+Faster Than Light, 2570 Ocean Ave. #114, San Francisco, California, 94132
+HTTP://www.ftl.net/ EMAIL:davis@ftl.net TEL:415.334.2922 FAX:415.337.6135
+
+We are located in the "Bay Area" of California, USA. We provide
+consultant and training for Unix, Windows, Macintosh applications,
+and hardware. We also provide Internet access to many of the local
+companies as a part of our "one-stop-shop" model.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SAN FRANCISCO BAY AREA - USA
+
+2125 Hamilton Ave. Suite 100
+San Jose, CA 95125
+888-ACCLAIM [Inside California]
+(408) 879 - 3100
+(408) 377-4900 [Fax]
+
+We can provide commercial support for Samba. We have created additional
+scripts that we can add to the Samba distribution to create an installation in
+Sun Solaris "package add" format. We are a Sun Reseller, but we can also
+support Samba on HP, SGI, Linux, in addition to Sun Solaris Sparc/X86.
+
+To find out more about our company, look at our website:
+ http://www.acclaim.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BAY AREA, BERKELEY CALIFORNIA - USA
+
+Vortex Technology Services
+
+2467 Warring St Suite 206, Berkeley CA 94704
+
+Phone/Fax : (510) 540-VTEX E-Mail: support@vtex.net
+ (510) 540-8839
+
+Contact: Paul Puey, Chief Network Consultant/Engineer
+
+Vortex Technology is a fast growing technical service company based in
+Berkeley, California. Our Co-founders are composed entirely of UC
+Berkeley engineering graduates with a broad range of skills in the
+technical consultation fields. We provide bay area companies with
+professional web site and database design, LAN and WAN consultation, and
+custom programming. We ourselves use a mixed NT / Linux Samba server
+environment in our office. We are very experienced with Samba
+administration as well as administration of UNIX and NT networks.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CALIFORNIA - USA
+
+Cliff Skolnick
+Steam Tunnel Operations
+900 Tennessee St, suite 22
+San Francisco, CA 94107
+http://www.steam.com/
+(415) 920-3800
+cliff@steam.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CALIFORNIA - USA
+
+Craftwork Solutions Inc.
+
+Craftwork Solutions Inc. is dedicated to providing the best possible
+services to our customers. The Craftworks team will provide you with a
+total solution package that will work for you both today and tomorrow.
+With our own Linux Distribution which we are constantly improving to make
+it the best and using it to provide total solutions for companies which
+are open to using Linux.
+
+Please contact mary@craftwork.com
+------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------
+SOUTHERN CALIFORNIA - USA
+
+Michael St. Laurent
+Serving Los Angeles and Orange Counties. Please contact via email.
+rowl@earthlink.net
+Michael St. Laurent
+Hartwell Corporation
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SOUTHERN CALIFORNIA - USA
+
+Yuri Diomin
+Yuri Software
+13791 Ruette Le Parc, Ste. C
+Del Mar, CA 92014
+Phone: 619-350-8541
+Fax: 619-350-7641
+yuri@yurisw.com
+http://www.yurisw.com
+
+We have been supporting Samba in commercial installations for several years
+on a variety of client and server platforms. We have extensive experience
+in all aspects of UNIX-Windows connectivity solutions for mixed platform
+corporate setups. We are a contributor to Samba source code.
+------------------------------------------------------------------------------
-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
+------------------------------------------------------------------------------
+NORTH CAROLINA - USA
+
+Whole Systems Solutions, Inc.
+
+ Whole Systems Solutions, Inc. has been running Samba since the
+1.6 release. We specialize in small to medium sized business network
+solutions. Whole Systems Solutions, Inc. provides outsourcing of IT to
+enhance employee abilities therefore improving productivity. Through
+software beta testing and development network of NT, NetWare, Unix, and
+Win clients we have developed a vast knowledge base for support. Our
+clients choose us for service and support that exceeds their
+expectations. Your business depends on your computers. Your computers
+should depend on WSS.
+
+Jay M. Eisenberg Whole Systems Solutions, Inc.
+President
+Web: http://www.wss.net
+Phone: (910) 297-4977
+Email: jay@wss.net
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FORT COLLINS, COLORADO - USA
+
+Granite Computing Solutions
+ATTN: Brian Grossman
+P.O. Box 270103
+Fort Collins, CO 80527-0103
+U.S.A.
+Tel: +1 (970) 225-2370
+Email: granite@SoftHome.Net WWW: http://www.SoftHome.Net/granite/
+
+Information services, including WfWG, NT, Apple <=> Unix interoperability.
+WWW solutions. WWW education. Unix education. Custom software
+development - eg. http://www.SoftHome.Net/modsim/.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+COLORADO - USA
+
+Daylight Software
+1062 Lexington Lane
+Estes Park, CO 80517 USA
+(970) 586-6058
+
+We have experience with Samba under SunOS, Solaris and Linux,
+and also with Windows NT and Microsoft Lan Manager.
+
+Contact: daylight@frii.net
+
+Chris Howard Daylight Software
+daylight@frii.net Estes Park, Colorado USA
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - 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)
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+Progressive Computer Concepts, Inc.
+1371 Cassat Avenue
+Jacksonville, FL 32205
+info@progressive-comp.com
+800-580-2640 - 904-389-3236 - 904-389-6584 fax
+
+Related Products and Services:
+ ncLinux (Network Computer) consulting, installations, and turnkey
+ networks. Multi-user NT and Samba consulting, installation and
+ administration (both remote and onsite), Internet and Intranet
+ connectivity, LAN and WAN, firewall installation, security,
+ troubleshooting and training, custom LAN/WAN/Intranet business
+ systems development, WWW/CGI development (e.g. database gateways,
+ catalogs).
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+Ten Twenty-Six Enterprises, Inc.
+1616 Illinois Street, Orlando FL 32803
+
+http://www.ten26.com/
+
+Email: samba@ten26.com
+
+Tel: 407 898-2519
+
+We are a commercial network and computer consulting firm providing
+hardware sales and network support.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+FLORIDA - USA
+
+TradeWeb
+Bill Harris
+(407) 657-8649
+bill@tradeweb.net
+
+http://www.tradeweb.net
+
+We have been working with SAMBA since 1995 and support it in a number of
+large organizations. We are available to Companies in the Central
+Florida area. We are well familiar in the integration of SAMBA and NT
+and in SAMBA configuration on AIX, SCO, Linux And SUN Solaris.
+------------------------------------------------------------------------------
-Samba experience: SVR4,SVR3.2 & Linux <--> WfWg, W3.1, OS2 and MS-LanMan
------------------------------------------------------------------------------
+FLORIDA - USA
+
+The PC Doctor
+Tampa Bay Interactive
+1314 Tampa Rd STE 120
+Palm Harbor, FL 34683
+
+ph 813.781-2209
+fx 813.571-3805
+
+Contacts: Jared Hall: jhall@tbi.net
+ System Operations: support@tbi.net
+
+Tampa Bay Interactive provides complete Internet solutions for the Small
+Office and Home Office. Specializing in Intel-Based UNIX systems; Linux,
+BSD/OS, FreeBSD, SCO. Proxy Server specialists.
+
+~~ Jared Hall ~~~~~~~ Tampa Bay Interactive
+~~~~~~~~~~~~~~~~~~~~~ 1314 Tampa Rd, #120
+~~ jhall@tbi.net ~~~~ Palm Harbor, FL 34683
+~~ (813) 781-2209 ~~~ (http://www.tbi.net)
+
+Telecom Corner - http://www.tbi.net/~jhall
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GEORGIA - USA
+
+Hoppe Computer Services
+2171 Brooks Road
+Dacula(Atlanta), Georgia 30019
+770-995-5099 fax 770-338-3885
+
+Supporting the Atlanta, Georgia USA area for two and a half years.
+In the computer field for 22 years.
------------------------------------------------------------------------------
-ILLONOIS - USA
+
+------------------------------------------------------------------------------
+GEORGIA - USA
+
+Region: ATLANTA, GA - USA
+Company: Advanced Application Development, Inc.
+Address: 4383 Burnleigh Chase
+ Roswell, GA 30075
+Telephone: (770) 552-4248
+email: support@aad.com
+Contact Name: Rich Vaughn
+ rvaughn@aad.com
+
+Provides consulting, development and system integration
+services for businesses throughout the Southeastern US.
+We have been using Samba on various UNIX platforms for
+several years and are familiar with porting and configuration
+issues. Visit our web site at http://www.aad.com.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+IOWA - USA
+
+Afan Ottenheimer
+JEONET
+PO Box 1282
+Iowa City, IA 52244
+Phone: 319-338-6353
+Fax: 319-338-6353
+Email: afan@jeonet.com
+WWW: http://www.jeonet.com/jeonet/
+
+Specializing in systems integration, database, and advanced web
+site design since 1995. Have extensive experience in
+Linux<->NT<->Windows 3.11<->Windows 95 interaction using SAMBA.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ILLINOIS - USA
Information One, Inc.
736 Hinman Ave, Suite 2W
@@ -61,103 +532,566 @@ Providing custom Internet and networking solutions.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
+ILLINOIS - USA
+
+Honesty Communications Inc.
+1001 W 75th St Suite 179A-200
+Woodridge, IL 60517
+
+http://www.honesty.com
+support@honesty.com
+
+(630) 964-8441
+(708) 399-8158 Emergency Pager
+
+Serving as 'Technical Support for Technical Support' to numerous
+companies across the country Honesty Communications provides
+solutions for all situations with
+
+We can provide Samba installation, configuration, and security analysis
+as well as on-going support, training and upgrades. We also provide
+custom programming and a slew of other services.
+
+Expertise includes:
+
+ UNIX, Windows 95, Windows NT, Windows 3.x, OS/2, Programming (C/C++,
+ Java, Visual Basic, Visual C, etc.), Support, Training
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+KANSAS - USA
+
+NT Integrators
+2400 W. 31st Street
+Lawrence, KS 66046
+USA
+913-842-1100
+http://www.ntintegrators.com/
+email: watts@sunflower.com
+
+My consulting company does NT/Linux/Samba/etc support.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+MISSOURI/KANSAS - USA
+
+DLP, Inc.
+303 N. Jeffreys Street
+Pleasant Hill, MO 64080-1331
+USA
+816-540-5167 - voice
+816-540-5218 - fax
+
+DLP, Inc. offers cost-effective networking solutions to small and
+medium-sized businesses in the greater Kansas City area using a
+combination of MS-Windows 95/NT workstations and Linux servers running
+samba. Services offered include complete system setup and configuration
+of new installations and enhancement and administration of existing
+installations. Other available services include installation and setup of
+intranets using the popular Apache web server.
+
+Please contact Dave Parker via email or call toll free from the greater
+Kansas City area:
+
+ 540-5167 - voice
+ 540-5218 - fax
+
+email: dlparker@dlpinc00.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LAS VEGAS, NEVADA - USA
+
+DPN, Inc. Las Vegas NV
+
+(702) 873-3282 Ph.
+(702) 873-3913 Fax
+Email duane@dpn.com
+
+Can provide commercial support for samba running on any version of
+SCO above 3.0 and for Linux. We currently have installed and are
+supporting several versions of samba on over 25 client sites across
+the US, in addition to our 6 in-house samba servers. Our largest client
+site has approx. 100 users.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+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.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NEW YORK - USA
+
+67.2 Psytronics Solutions
+
+ 90 County Line Road
+ Massapequa, NY 11758
+ U.S.A.
+
+Phone: +1 516 598 4619
+
+Fax: +1 516 598 4619
+
+EMail: info@psytronics.com
+
+URL: http://www.psytronics.com
+
+Contact: Jaron Rubenstein
+
+Type of support: Whatever is required. Support contracts available.
+
+Special expertise:
+
+ Familiar with most topics. Specializing in dial-up server (PPP)
+installation and configuration, custom programming, and Internet and
+Intranet server configuration. Authorized Red Hat Reseller.
+
+Sample prices:
+
+ Upon request, usually US$50-$100/hour. Educational discounts
+available.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+OREGON - USA
+
+Warren Birnbaum
+Birnbaum Associates
+2934 N.E. 18th Avenue
+Portland, OR 97212
+Phone: 503-282-6329
+Fax: 503-288-7074
+birnbaum@teleport.com
+
+I have been supporting Samba in commercial installations for several
+years on HP-UX and Solaris server platforms. I have installed Samba on
+over 80 servers used by over 7000 users. I am a contributor to Samba
+source code.
+
+I can provide Samba installation, configuration, and custom coding
+as well as on-going support.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+TEXAS - USA
+
+Jody Winston
+xprt Computer Consulting, Inc.
+731 Voyager
+Houston, TX 77062
+(281) 480 8649, jody@sccsi.com
+
+We have been supporting software from the Free Software Foundation and
+other groups such as Linux for over 8 years. The base rate is 150.00
+US dollars per hour. Please contact us for more information on our
+rates and services.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+TEXAS - USA
+
+The Solutions Group
+P.O. Box 31400
+Houston, TX 77231-1400
+
+Voice: (713) 729-2602
+Fax: (713) 723-9387
+Email: chuckb@LinuxTX.com
+
+The Solutions Group provides support for Linux, Solaris, and SCO UNIX.
+We specialize in mixed environments using Samba. We are certified NT
+as well as UNIX specialists. We can provide onsite support in the
+Houston area and remote support in any other areas.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+UNITED STATES
+
+Stelias Computing is the developer of the InfoMagic Workgroup Server, a
+Linux distribution customized for use as a PC and Macintosh file and
+print server (using Samba and netatalk respectively). Stelias also
+offers custom system programming and Samba support contracts.
+
+For information about the InfoMagic Workgroup Server contact InfoMagic:
+ http://www.infomagic.com/
+ questions@infomagic.com
+ voice: 800-800-6613 or 520-526-9565
+ fax: 520-526-9573
+
+To contact Stelias about custom arrangments, send email to
+info@stelias.com.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+USA / CANADA
+
+Shakeel Software Systems. - USA/Canada
+
+Shakeel Ahmed Rao
+E-mail: sarao@ibm.net
+Phone: (773) 695-0104 USA (519) 570-0468 Canada
+
+
+Expertise in implementing Samba in Unix/NT/WIN95 client/server environments.
+Have successfully implemented SAMBA for Hewlett Packard and IBM intranets.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+USA - VIRGINIA
+
+Commonwealth Technical Services, Inc.
+13618 Hull Street Road
+Suite 300
+Midlothian, VA 23112
+bcaudle@ctsi.net
+www.ctsi.net
+804-639-5400
+
+Commonwealth Technical Services supports Samba systems on various UNIX platforms,
+as well as providing hardware, software, and consulting services for UNIX and Windows
+networks and the Internet.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+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
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WASHINGTON STATE - USA
+
+Brian Meyer
+Personal Data Services
+9792 Edmonds Way Suite 121
+Seattle, Washington 98020 USA
+Voice: (206) 365-8212
+E-mail: admin@pdsnorth.com
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WASHINGTON - USA
+
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.
+WASHINGTON STATE - USA
-Mauro DePalma <mauro@sru.com>
+INTERNET: bill@Celestial.COM Bill Campbell; Celestial Systems, Inc.
+UUCP: camco!bill PO Box 820; 2835 82nd Avenue S.E. S-100
+FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
+URL: http://www.celestial.com/
+
+We provide support for Samba and many other Unix related systems. Our
+primary systems are SCO, Caldera Linux, and Solaris on Sun systems.
+
+Celestial has been in business since late 1984 working primarily on
+medium to large Unix systems. More information is available on our
+web site, http://www.celestial.com/.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-BIELEFELD - GERMANY
+WASHINGTON STATE - USA
-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.
+Jeff Clithero jeff@octopi.com APPGEN Vertical
+Interstellar Octopus, Ltd. Voice 360-379-1754 Accounting Solutions
+1829 Lincoln St. PgVm 800-893-9517 Integration Services
+Port Townsend, WA USA FAX 360-379-1753 Sales and Support
+
+We support SAMBA commercially.
+
+In the US/Canada we provide 800 number for our clients and can go
+onsite to customers in the Northwest US and Vancouver, BC areas.
------------------------------------------------------------------------------
+
+
+ASIA
+====
+
------------------------------------------------------------------------------
-CANBERRA - AUSTRALIA
+SEOUL - KOREA
-Ben Elliston
-Faculty of Information Sciences and Engineering
-University of Canberra AUSTRALIA
-E-mail: ben@ise.canberra.edu.au (Uni)
+MultiMedia KOREA Inc, E-Mail : info@seoul.korea.co.kr
+Internet,WWW,Network Support Group, TEL : +82-02-597-1631
+ FAX : +82-02-521-4463
+SeoChoGu SeoChoDong 1537-6 WWW : http://www.korea.co.kr
+JungAng B/D #401
+SEOUL KOREA
+
+SAMBA Experience : SunOS, Solaris, Linux, SCO-Unix, Win95/NT/3.1
------------------------------------------------------------------------------
+
+
+
+
+
+AUSTRALIA & NEW ZEALAND
+=======================
+
------------------------------------------------------------------------------
-PALERMO - ITALY
+ADELAIDE - AUSTRALIA
-Francesco Cardinale
-E-Mail: cardinal@palermo.italtel.it
-Samba experience: SVR3.2, SOLARIS, ULTRIX, LINUX <--> DOS LAN-MAN, WFW
+Richard Sharpe, sharpe@ns.aus.com
+NS Computer Software and Services P/L
+PO Box 86,
+Ingle Farm, SA 5098
+Australia
+
+Contact: Richard Sharpe
+ Ph: +61-8-281-0063 (08-281-0063) AH
+ FAX:+61-8-250-2080 (08-250-2080)
+
+Located in Adelaide, South Australia.
+
+Proficient with Digital UNIX, ULTRIX, SunOS, Linux, Win 95, WfWg, Win NT.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-SYDNEY - AUSTRALIA
+ADELAIDE - AUSTRALIA
-John Terpstra - Aquasoft (jht@aquasoft.com.au)
-Business: +612 524 4040
-Home: +612 540 3154
-Shoephone: +612 414 334422 (aka 0414 334422)
+Loftus Computing Services
+191 Flinders Street
+Adelaide 5000
+South Australia
+
+Phone: +61 8 8407 7577
+Fax: +61 8 8407 7501
+Email: support@loftuscomp.com.au
+
+
+SAMBA Experience : SunOS, Solaris, SCO-Unix, Free BSD, Win95/NT/3.1
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-ONTARIO - CANADA
+CANBERRA - AUSTRALIA
-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/
+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.
+------------------------------------------------------------------------------
-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.
+------------------------------------------------------------------------------
+CANBERRA - AUSTRALIA
+
+Ben Elliston
+E-mail: bje@air.net.au
+Samba systems: Solaris 2.x, Linux, HP-UX.
------------------------------------------------------------------------------
-----------------------------------------------------------------------
-SYDNEY - AUSTRALIA
+MELBOURNE - 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)
+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.
-----------------------------------------------------------------------
------------------------------------------------------------------------------
-EDINBUGH - SCOTLAND
+MELBOURNE - AUSTRALIA
-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
+Company Name DARX Consulting
+Postal Address PO Box 12329
+ A'Beckett St PO
+ Melbourne 3000
+Area of Service Melb Metro and SE Suburbs
+Phone +61 3 9822 1216
+Email info@darx.com.au
+
+We provide setup and support of samba based systems as well as
+Novell/NT Systems.
+-----------------------------------------------------------------------
-SAMBA experience: SCO UNIX <=> WfWg
------------------------------------------------------------------------------
+N.T - AUSTRALIA
+
+Open Systems Network SupportServer Platforms -
+Unix/Linux
+Client Platforms - Windows3.1/95/NT, Macintosh, Unix/Linux--
+David Schroeder Darwin Network Services
+Ph/Fax (08) 8932 1156 PO Box 82383
+(Int) +61 8 8932 1156 Casuarina N.T
+Email: djsc@it.ntu.edu.au Australia 0811
+-----------------------------------------------------------------------
------------------------------------------------------------------------------
-LONDON - ENGLAND
+NEW SOUTH WALES - AUSTRALIA
+
+BITcom Telecommunications Phone: (02) 9747 0011
+P.O. Box 15 Int'l: +61 2 9747 0011
+Burwood NSW 2134 Australia Fax: (02) 9747 6918
+Contact: Craig Bevins Email: consult@bitcom.net.au
+
+BITcom is an open systems and networking consultancy. We have been
+doing Open Systems since long before the term was coined, a key staff
+member having participated in the IEEE working group which produced
+the POSIX standard for Un*x-like systems in 1988.
+
+We tend to have a Unix orientation (all flavours) but our focus is on
+getting the job done and we are happy to employ other technologies which
+fit. Heck, we even use and support Microsoft's products! Our areas
+of expertise cover general Unix consultancy, support for public domain
+and GNUish software, PC LAN -> Unix integration, Internet, WWW and local
+and wide-area network design, implementation and security. We have a
+collective masochistic streak and actually enjoy hacking on sendmail
+configuration. We are an AUSTEL-licenced telecommunications and data
+cabler and hold a NSW security industry licence.
+
+We know Windows NT, LANMAN, PC-NFS and others. We use, recommend and
+support Samba and have done so since 1994.
+------------------------------------------------------------------------------
-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
+------------------------------------------------------------------------------
+PERTH - AUSTRALIA
+
+Bruce Cook - Synonet Corporation.
+E-mail: bcook@wantree.com.au
+Mobile: 015 999 330 (International +61 15 999 330)
+Experience: Samba on FreeBSD, Linux, Solaris (Sparc), Sunos-4
+ Microsoft networking using NT/NTAS, Win95, WFW311, DOS
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PERTH - AUSTRALIA
+
+Geoff Allan Phone: +61 8 9325 9922
+Office Information Fax: +61 8 9325 9938
+Perth, Western Australia Mobile: 0412 903 659
+Email: geoffa@officeinfo.com.au
+
+Office Information has been in existence since 1991. We are (amongst
+other things) systems integrators with experts in Unix, Linux, Novell,
+NT and the other DOS & Windows platforms. We also have a number of
+Clients for whom we have installed and supported Samba.
+------------------------------------------------------------------------------
-Samba Experience:
-Server: Solaris 2.3 & 2.4, Irix 5.2 & 5.3
-Client: WinNT, Win95, WfWg, Win3.1, Ms-LanMan, DHCP support
+------------------------------------------------------------------------------
+PERTH - AUSTRALIA
+
+CONDOR Technology Pty Ltd
+12 Walker Avenue,
+West Perth, WA, 6005.
+
+Phone: +61-8-9322-2377
+Fax: +61-8-9322-2380 (fax)
+Mail: sales@condor.com.au
+
+As UNIX specialists since 1989, the team at Condor
+provide unmatched expert advice for UNIX file serving,
+communication, intranet, World Wide Web and mail servers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+QUEENSLAND - AUSTRALIA
+
+OPAL BROOK Pty Ltd.
+Dave Forden
+The Software Systems & Technology Consulting Specialists
+Unit 120 Admiralty Towers 1, 35 Howard Street BRISBANE QLD 4000
+Business: 38318251
+Mobile: 041 996 5577
+email: opalbrk@bit.net.au
+web: http://bit.net.au/~opalbrk
+
+ON SITE: FOCUS98 Project - Queensland Department of Natural Resources
+fordendk@exchange.lands.qld.gov.au
+Unit6 Level3 Anzac Square Building Brisbane
+(07) 3227 6265
+
+My company provides general Unix based development and support services in
+Brisbane.
+
+Personally, I have been using SAMBA for about 2 years and have implemented
+it on several different Unix platforms including HPUX, Linux, Dynix, and
+Solaris.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+QUEENSLAND - AUSTRALIA
+
+Plugged In Software Pty Ltd
+PO Box 4130
+4/242 Hawken Drive
+St. Lucia South, Qld 4067
+Australia
+http://www.plugged.net.au
+info@plugged.net.au
++61 7 3876 7140
++61 7 3876 7142 (fax)
+Point of Contact: David Wood
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SYDNEY - AUSTRALIA
+
+Philip Rhoades
+Pricom Pty Ltd
+http://www.pricom.com.au = http://203.12.131.20
+GPO Box 3411 Sydney NSW 2001 Australia
+Ph: +61:0411:185652
+Fax: +61:2:9959-3481
+E-mail: philr@mail.austasia.net
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SYDNEY - AUSTRALIA
+
+John Terpstra - Aquasoft (jht@aquasoft.com.au)
+Business: +612 9524 4040
+Home: +612 9540 3154
+Mobile: +612 414 334422 (aka 0414 334422)
+Samba Experience: Member of Samba-Team. Long term contributor to Samba
+ Samba on BSD/OS, Solaris (Sparc & x86), ISC Unix, SCO Unix
+ NCR SVR4, Linux, UnixWare, IBM, HP, DEC, Others.
+ Training Instructor in Windows NT, wide area networking
+ over TCP/IP. Providing paid-for support for Public Domain
+ Software and Linux.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+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)
------------------------------------------------------------------------------
------------------------------------------------------------------------------
@@ -179,126 +1113,186 @@ info@eram.esi.com.au Voice:+61-2-9063377
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-CHANTILLY - USA
+WELLINGTON - NEW ZEALAND
+
+David Gempton
+Computer Consultant
+UNIX & PC Networking specialist
+TTC Technology Training Consulting
+PO Box 5444
+Lambton Quay Wellington
+New Zealand
+Phone (025) 518-574
+Email: ttcdg@cyberspace.co.nz
+------------------------------------------------------------------------------
-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.
+
+
+
+
+CANADA
+======
+
------------------------------------------------------------------------------
+ALBERTA - CANADA
+
+GDS & Associates Systems Ltd.
+1010 First Edmonton Place
+10665 Jasper Ave.
+Edmonton, AB
+Canada T5J 3S9
+
+http://www.gds.ca/
++1 403 426 4484
+FAX: 426 2898
+
+Contact: Iain O'Cain <iocain@gds.ca>
+
+GDS is an information management consulting company with headquarters in
+Regina, Saskatchewan, and offices across Western Canada. The Edmonton
+office offers Systems Management services covering a variety of Unix and
+similar server operating systems.
------------------------------------------------------------------------------
-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
+------------------------------------------------------------------------------
+ALBERTA - CANADA
-Information services, including WfWG, NT, Apple <=> Unix interoperability.
+Distributed Computing Experts Corp.
+407, 1167 Kensington Cres. N.W.
+Calgary, Alberta T2N 1X7
+
+Tel: +1 (403) 630-5931 Fax: +1 (403) 278-8437
+Email: WWW: http://www.dcexpert.ab.ca
-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 <
+Distributed Computing Experts Corp. (DC Experts) is an
+Information Systems Consultancy in Calgary. We can provide
+systems administration and systems programming for IBM AIX, Sun
+Solaris, Hewlett-Packard HP-UX, DEC Digital Unix, Silicon
+Graphics IRIX, BSD, Linux, and Windows NT. Management of TCP/IP
+network infrastructures, security consultanting, Internet
+firewalls and configuration of Internet services are also a
+forte. Our personnel have been installing and configuring Samba
+since 1995.
------------------------------------------------------------------------------
-----------------------------------------------------------
-Adelaide, Australia
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-NS Computer Software and Services P/L
-PO Box 86
-Ingle Farm
-SA 5098
+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/
-Contact: Richard Sharpe
- Ph: +61-8-281-0063 (08-281-0063) AH
- FAX:+61-8-250-2080 (08-250-2080)
+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.
+------------------------------------------------------------------------------
-Experience with: ULTRIX, Digital UNIX, SunOS, WfW 3.11, Win95, WNT 3.51
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-----------------------------------------------------------
+WW Works Inc.
+3201 Maderna Road
+Burlington, Ontario
+Canada L7M 2W4
-----------------------------------------------------------
-TECTONIC LIMITED
-WESTWOOD
-78 LOUGHBOROUGH ROAD
-QUORN
-LEICESTERSHIRE
-LE12 8DX
+Contact: Wade Weppler
+(905) 332-5844
+FAX: (905) 332-5535
-TELEPHONE 01509-620922
-FAX 01509-620933
+Information Systems Sales and Consulting.
+Specializing in Turnkey Windows NT Network environments with emphasis on
+Legacy UNIX System integration using Samba.
+------------------------------------------------------------------------------
-CONTACT DAVID ROBINSON
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-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.
+Sound Software Ltd.
+20 Abelard Avenue
+Brampton, Ontario Canada
+905 452 0504
+sales@telly.org
+www.telly.org
-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
-----------------------------------------------------------
+Sound Software company is a Caldera Business Partner, providing support for
+Samba and other applications running under Caldera Linux.
+------------------------------------------------------------------------------
-----------------------------------------------------------
-MIAMI, FL - USA
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-Swaney & Associates, Inc.
-ATTN: Stephen Swaney
- 2543 Lincoln Avenue
- Miami, Florida 33133
- U.S.A
- (305) 860-0570
+GenX Internet Laboratories Inc.
+20 Madison Ave.
+Toronto, Ontario, Canada
+M5R 1S2
-Specializing in:
- High Availability system & networks
- UNIX to PC connectivity
- Market Data systems
- Messaging Systems (Sendmail & Microsoft Exchange)
-----------------------------------------------------------
+GenX Internet Labs is engaged in systems integration and
+the design and development of software for use over the
+internet and intranets.
+We install, support and can resolve most system/Samba problems
+on Linux. We are also an internet provider and use Samba to
+provide a remote office solution to our customers. This solution
+provides access to the shared resources on a corporate lan.
------------------------------------------------------------------------------
-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
+------------------------------------------------------------------------------
+ONTARIO - CANADA
- Specializing in Internet connectivity and security, Sun integration and
- high speed, enterprise network design and deployment.
+FSC Internet
+The FSC Building
+188 Davenport Rd
+Toronto, Ontario
+Canada M5R 1J2
+
+(416) 921-4280
+fax (416) 966-2451
+
+info@fscinternet.com
+
+FSC Internet is one of Canada's largest UNIX and NT networking
+consulting firms. FSC's clients include numerous top-tier
+corporations (e.g. Mazda, Heinz), as well as mid-sized companies
+(e.g. the Vermont Telephone Company) and the public sector. FSC
+provides full consulting, implementation, support, and training
+services for all UNIX and NT network applications, including a
+special focus on internetworking (extensive Samba experience),
+security, high-performance Web applications, and Intranets. Please
+email us at info@fscinternet.com or call us at (416) 921-4280 for
+further information.
------------------------------------------------------------------------------
-FAREHAM - ENGLAND
+------------------------------------------------------------------------------
+ONTARIO - CANADA
-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
+MIS Incorporated, London Ontario CANADA
+Tel: +1 (519) 673-3777 Fax: +1 (519) 673-4292
+Email: samba-support@netcontech.com
-Company skills: Real time hardware and software systems
+MIS Incorporated is a Microsoft Certified Solution Provider,
+and system support group specializing in applying Windows
+front ends to high end relational database servers. Samba
+support available on any unix platform in conjunction with
+WFW, Windows-NT, Win95, OS/2. Dial-in support
+nation-wide, or on-site anywhere in Ontario.
+------------------------------------------------------------------------------
-Samba experience: BSD/OS, Linux, LynxOS <==> WFWG, NT
+------------------------------------------------------------------------------
+OTTAWA - CANADA
+Russell McOrmond
+Open Systems Internet Consultant
+Serving individuals and organizations in the Ottawa (Ontario, Canada) area.
+voice: (613) 235-7584 FAX: (613) 230-1258
+russell@flora.org , http://www.flora.org/russell/work/
------------------------------------------------------------------------------
------------------------------------------------------------------------
+------------------------------------------------------------------------------
QUEBEC - CANADA
Dataden Computer Systems
@@ -316,61 +1310,835 @@ 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
+
+EUROPE
+======
-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
+VIENNA - AUSTRIA
-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.
+Company: Peter-Paul Witta
+Contact: Peter-Paul Witta, paul@ping.at
+keywords: SAMBA, Unix, Linux, OS/2, WinNT, Win95, Support, Consulting,
+ Installation, System Administration.
+
+Experience: Domain Browsing, Logon-Scripts, SAMBA Integration into Domains,
+ SAMBA as Domain Master, Printing, Faxing with IntraFax (our own Fax product),
+ Sendfax and Samba.
+
+Feel free to call: +43-1-6171288
+
+Various ranges of consulting and maintenenace contracts available.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BRUSSELS - BELGIUM
+
+Phidani Software SPRL
+Rue de l'autonomie, 1
+1070 Brussels
+Belgium
+Tel : +32 (2) 5220663
+Fax: +32 (2) 5220930
+
+We provide commercial support in Belgium to large organisations
+(eg: N.A.T.O., Unisys, E.C.C. ...)
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SOFIA - BULGARIA
+
+National Laboratory for Computer Virology and SEA Ltd.
+
+We work mainly in the following fields:
+
+* Design and testing of antivirus and computer security related software
+ and hardware;
+* Data aquisition equipment
+* Network design and consulting.
+
+Samba is our most common network tool for the export of data collected on
+UNIX machines to PC clients, file services and simple client/server
+processing schemes.
+
+Samba experience: Linux, Ultrix, Solaris, AIX, RiscOS.
+
+Client experience: LanMan, WFW, Win 95, Win NT.
+
+Address:
+
+National Laboratory for Computer Virology BAS,
+Akad. G. Bonchev Str. bl.8,
+Sofia 1113,
+Bulgaria
+E-mail:sales@nlcv.acad.bg
+URL http://www.nlcv.acad.bg
+
+SEA Ltd,
+Akad G.Bonchev Str bl. 8, rm 225,
+Sofia 1113.
+Bulgaria
+E-mail:nmechkov@virbus.bg
+URL http://www.orgchm.acad.bg/~sealtd
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PRAHA (PRAGUE) - CZECH
+
+AGC Praha,
+David Doubrava
+Sokolovska 141
+PRAHA 8
+180 00
+
+Tel: +42 (2) 6600 2202 Fax: +42 (2) 683 02 55
+Email: ddoubrava@agc.cz WWW: http://corwin.agc.cz/
+
+I have Samba experience with Windows NT,
+Windows 95, and Windows for Workgroups clients with Linux and HP-UX
+servers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CAMBRIDGE - ENGLAND. Will travel / provide support world-wide.
+
+Luke Kenneth Casson Leighton
+Phone: +44 1223 570 262 or 570 264 or Mobile +44 410 305 745
+lkcl@switchboard.net
+
+Configuration Experience:
+
+Clients: MSClient 3.0; WfWg; W95; NT 3.5 and 4.0 Workstation.
+Servers: Samba 1.9.15 and above (on-hands experience with Linux, SunOS
+4.1.3 and FreeBSD); NT 4.0 Server.
+
+Present Experience:
+
+Luke Leighton, a Samba Team member since October 1995, understands
+Browsing and WINS from having re-designed and re-written nmbd, and
+SMB/CIFS from attending the two CIFS conferences; by listening to
+discussions amongst the Samba Developers, and from answering user's
+queries on the Samba Digest.
+
+Support offered:
+
+If there are either areas of functionality that are missing or bugs
+that are affecting the performance of your company; if you require
+advice / training on the deployment and administration of SMB/CIFS
+Clients and Servers; if your company's policy only allows you to
+use samba if it is supported commercially... I am available for hire
+anywhere in the world.
+
+Long-term Project Aims:
+
+I would like to implement a CIFS proxying system suitable for Enterprise
+Networks (large Intranets: 10,000 to 150,000 simultaneous users) that is
+backwards compatible with all CIFS/SMB servers (MSClient 3.0 for DOS,
+through to NT 4.0).
+
+I would also like to implement an alternative SMB client for NT and 95.
+This would allow samba to offer secure and authenticated file and print
+access, to the extent that the laws of your country permit.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CAMBRIDGE - ENGLAND
+
+Mark Ayliffe MBCS, Technical Consultant
+Protechnic Computers Limited http://www.prot.demon.co.uk
+7 Signet Court Tel +44 1223 314855
+Swann's Road Fax +44 1223 368168
+Cambridge CB5 8LA
+England
+
+
+Protechnic Computers Limited has experience of installing and
+maintaining Samba on the following platforms:
+
+HP/UX 9.0x, 10.1x & 10.2x
+DG/UX, Motorola and Intel
+Digital UNIX
+------------------------------------------------------------------------------
-David J. Fenwick Asset Software, Inc.
-President djf@assetsw.com
------------------------------------------------------------------------------
+CORNWALL - ENGLAND
+Starstream Communications Ltd
+Unit 9
+Moss Side Industrial Estate
+Callington
+Cornwall
+PL17 7DU
+United Kingdom
+
+Phone +44 1579 384072 Fax +44 1579 384267
+
+Contact : Terry Moore-Read terry@starstream.co.uk
+
+Website : http://www.ndu-star.demon.co.uk shortly moving to
+http://www.starstream.co.uk
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+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
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LEICESTERSHIRE ENGLAND
+
+TECTONIC LIMITED
+WESTWOOD
+78 LOUGHBOROUGH ROAD
+QUORN
+LOUGHBOROUGH
+LEICESTERSHIRE
+LE12 8DX
+UNITED KINGDOM
+
+Telephone: +44 (0) 1509 620922 Fax: +44 (0) 1509 620933
+
+Contact: Nick Berry nick.berry@tectonic.co.uk
+
+Tectonic is a Unix specialist company, with the expertise to provide
+consultancy and integrated solutions for a wide range of Information
+Technology needs. We support three major Unix operating systems (Solaris,
+AIX and HP-UX) and PC operating systems including Windows NT, Windows 95
+and Windows for Workgroups. Tectonic is truly an Open Systems company.
+
+Tectonic has been using Samba in house and providing support since 1995.
+We currently support a dozen large organizations in varying business
+sectors including business critical areas.
+
+Tectonic provides Samba support, technical expertise, upgrades and
+information bulletins.
+
+For more information about support please contact:
+nick.berry@tectonic.co.uk
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+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
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LONDON - ENGLAND
+
+Name: Paul Dunne
+Address: 30 Onslow Gardens
+ London
+ N10 3JU
+ UK
+Phone: +44 (0)181-374 8194
+Fax: None
+E-mail: paul@tiny1.demon.co.uk
+URL: http://www.tiny1.demon.co.uk
+
+Contact: Paul Dunne
+Type of support: E-mail and onsite.
+
+Expertise: Installing and troubleshooting Samba, on Linux and Win95.
+Sample prices: Basic rate £30/hour.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NEWCASTLE UPOON TYNE - ENGLAND
+
+New Mode Technology Limited, Newcastle Upon Tyne, UK
+Tel 07050 606 991 Fax 07050 606 992
+EMAIL : newmode@unforgettable.com.
+
+Support Available:
+
+Consultancy
+
+Design and Implementation of Networking solutions based on Samba and other
+protocols. Integration and migration between Unix and NT.
+
+All consultants are Microsoft Certified, and have implemented and suported Samba
+for several large clients on AIX and Solaris.
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+READING - ENGLAND
+
+Philip Hands | E-Mail: info@hands.com Tel:+44 118 9545656
+Philip Hands Computing Ltd. | Mobile: +44 802 242989 Fax:+44 118 9474655
+Unit 1, Cherry Close, Caversham, Reading RG4 8UP ENGLAND
+
+Samba experience:
+ Server platforms: Linux,SVR4,SVR3.2 & Sequent ptx
+ Clients: WfWg, W3.1, OS2 and MS-LanMan
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PARIS - FRANCE
+
+ALCOVE
+12, place Indira GANDHI
+92230 GENNEVILLIERS
+FRANCE
+
+Email: alcove@alcove.fr
+Web: http://www.alcove.fr
+
+Tél : 33 1 47 33 82 84
+Fax : 33 1 47 33 76 98
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BERLIN - GERMANY
+
+Name: innominate
+ Multifunktionale Serverloesungen und IT-Dienstleistungen
+
+Address: Gipsstrasse 3, 10119 Berlin
+Country: Germany
+Phone: +49 30 308 806-0
+Fax: +49 30 308 806-77
+EMail: info@innominate.de
+Web: http://innominate.de
+
+Type of support: vor Ort, Email, Fernzugriff ueber Internet/ISDN,
+
+Wir verfuegen ueber umfangreiche Erfahrung mit Samba, vor allem
+in Intranetumgebungen. Neben Beratung, Dienstleistung
+und Schulung bieten wir auch individuell vorkonfigurierte
+Kommunikationsserver ("Lingo") auf der Basis von Linux an.
+Neben anderen Modulen (ISDN/Internet/Intranet/Email/Proxy
+u.a.) ist in Lingo ein Fileserver-Modul auf Samba-Basis inklusive
+einem mehrstufigen Firewallsystem enthalten.
+Außerdem verfuegt Lingo ueber eine grafische Administrations-
+oberflaeche, mit der z.B. das Hinzufuegen von neuen Benutzern
+von jedem Client per WWW-Browser moeglich ist.
+
+Prices: Komplettpreise fuer Lingo nach Vereinbarung
+ 120 DM/Stunde fuer Dienstleistung
+ Schulung nach Vereinbarung
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BERLIN - GERMANY
+
+Ing. Buero Buehler
+Dipl.-Ing. Frank Buehler
+Paul-Krause-Str. 5
+14129 Berlin
+Germany
+
+Phone: +49/(0)177/825 33 80 Fax: +49/(0)30/803-3039
+mailto:fb@hydmech.fb12.TU-Berlin.de
+
+We install and maintain small to middle sized Linux-Windows
+networks within the Berlin area and are available for consulting and
+questions about networking, Linux, database systems and electronics.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+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.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BIELEFELD - GERMANY
+
+Name : media engineering gmbh
+Address: Bleichstr. 77a , D-33607 Bielefeld
+Phone : +49-521-1365640
+Fax : +49-521-1365642
+eMail : info@media-eng.bielefeld.com
+URL : http://www.media-eng.bielefeld.com/
+Contact: Dipl.Ing. Hartmut Holzgraefe
+
+Type of support: phone, eMail, inhouse, remote administration
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+DREIEICH - GERMANY
+
+A. G. Schindler <schindler@az1.de>
+c/o Alpha Zero One Gmbh
+Frankfurter Str. 141
+D - 63303 Dreieich
+Germany
+
+AZ1 is a company of Value Added Resellers (VARs) of Digital Equipment
+Corp. products and solution provider for Industry Applications.
+
+We're providing commercial support for Samba running on DEC hardware
+under Digital Unix (R), Digital OpenVMS (R) and Linux.
+
+Contract based and hotline support available. Fast response on-site
+support coming soon for the Franfurt / Main area.
+
+Pathworks or WinNT to Samba migrators welcome !
+
+Please contact us via: schindler@az1.de
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GOETTINGEN - GERMANY
+
+Service Network GmbH
+Hannah Vogt Str. 1
+37085 Goettingen
+Germany
+Phone: +49-551-507775
+Fax: +49-551-507776
+http://www.sernet.de/
+samba@sernet.de
+
+SerNet is a company doing LAN consulting and training. We offer
+Internet access for our customers. We have experience with many
+different kinds of Unix, especially Linux, as well as NetWare and NT.
+Volker Lendecke, one of our our founders and a Samba Team member,
+has gained a lot of SMB/CIFS and NetWare experience writing smbfs and
+ncpfs, the Linux kernel file systems that enable Linux to access
+Windows NT and other SMB/CIFS servers, and NetWare Servers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GREIFSWALD - GERMANY
+
+Mr. Frank Rautenberg, Mr. Heiko Boesel, Mr. Jan Holz
+UniCon Computersysteme GmbH
+Ziegelhof 20
+D-17489 Greifswald
+email: samba@unicon-gmbh.com
+www: http://www.unicon-gmbh.com
+
+We use Samba and we provide support for our customers.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+MUENCHEN - GERMANY
+
+CONSYS GmbH
+Landsberger Str. 402
+81241 München
+Germany
+Phone: +49-89-5808181
+Fax: +49-89-588776
+http://www.consys.de/
+mailto:samba@consys.de
+
+
+CONSYS is a software company. We have experience especially with SCO Unix
+and other Unix systems, as well as with Windows 95 and NT.
+We are a Premium Partner of SCO and know and have used samba for four years.
+Our engineers know a lot about the installation of SCO Unix.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GREECE
+
+Yiorgos Adamopoulos
+Electrical and Computer Engineer
+email: adamo@InterWorks.org
+
+I can provide Samba support for the following operating systems throughout the
+whole of Greece: Windows 3.11/95/NT, Ultrix, HP-UX, NetBSD, OpenBSD, SunOS,
+Solaris, Linux, Irix.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SZEGED - HUNGARY
+
+ Name: Geza Makay
+ Institute: Jozsef Attila University of Szeged
+ Mail: Bolyai Institute, Aradi vertanuk tere 1.
+ H-6720, Szeged, Hungary
+ Tel: (62) 454-091 (Hungary's code: 36)
+ Fax/Message: (62) 326-246 (Hungary's code: 36)
+ E-mail: makayg@math.u-szeged.hu
+ World Wide Web: http://www.math.u-szeged.hu/
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+MILANO - ITALY
+
+INFERENTIA S.p.A.
+Via Tacito 6
+20137 MILANO (MI)
+ITALY
+tel: +39 2 599281
+fax: +39 2 59928221
+contact: Consulting Division
+e-mail: consulting@inferentia.it
+www: http://www.inferentia.it
+
+INFERENTIA Consulting is available for establishing commercial support
+contracts on Samba integration with Microsoft Networks-based LANs.
+We can offer a solid experience with:
+- All flavours of Windows (Workgroups, 95, NT)
+- IBM AIX, Digital UNIX, Sun Solaris, Linux, HP/UX
+- geographically distributed networks with WAN links
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ITALY
+
+InfoTecna di Cesana D. & C. s.n.c.
+Via Cesana e Villa, 29
+20046 Biassono (Mi)
+
+Tel: ++39 39 2324054
+Fax: ++39 39 2324054
+
+e-mail: infotecn@tin.it
+URL: http://space.tin.it/internet/dsbragio
+
+We provide Samba support along with generic Linux support. Specifically we
+have implemented a powerful Fax servicing system for Samba with Win95/NT
+clients. Details could be found at our URL, currently, only in Italian.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ABANO TERME (PADOVA) - ITALY
+
+PROFUSO di Zanetti Giuseppe - Studio di Consulenza Informatica
+Abano Terme (PD) - ITALY
+profuso@profuso.com
+http://www.profuso.com/
+Phone: ++39 49 8059070 / ++39 348 2220811
+
+We provide all possible support for Linux, UNIX,
+development, security and system integration.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PALERMO - ITALY
+
+Francesco Cardinale
+E-Mail: cardinal@palermo.italtel.it
+Samba experience: SVR3.2, SOLARIS, ULTRIX, LINUX <--> DOS LAN-MAN, WFW
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+PISA - ITALY
+
+I3 ICUBE s.r.l.
+Via Pascoli 8
+56125 PISA (PI)
+ITALY
+tel: 050/503202
+fax: 050/504617
+contact person: Marco Bizzarri
+e-mail: m.bizzarri@icube.it
+www: http://www.icube.it/
+
+Our company offers commercial support to integrate eterogenous networks.
+We can provide support for the following architectures:
+
+Windows:
+Windows for Workgroup
+Windows 95
+Windows NT
+
+Unix:
+Linux
+Solaris
+Digital Unix
+
+Macintosh
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ROME - ITALY
+
+Company: Pantheon Srl
+ Via del Tritone 132
+ 00187 ROME - ITALY
+
+Phone/Fax: +39 6 47823666
+URL: http://www.pantheon.it
+
+Contact: Dario Centofanti <dario@pantheon.it>
+
+Pantheon provide support for SaMBa and other TCP/IP applications running
+under Linux. We are also an internet provider.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ITALY
+
+Sedac S.a.S.
+
+Piazza XX Settembre, 68
+62012 Civitanova Marche (MC)
+Italy
+
+Tel. : +39 (733) 810257-817064
+Fax : +39 (733) 819008
+PPP : +39 (733) 819009
+E-mail : sedac@cognigni.com
+WWW : http://www.cognigni.com/sedac
+
+La Sedac S.a.S. e' specializzata nell'implementazione ed amministrazione di
+reti eterogenee LAN/WAN basate sui sistemi operativi SCO Open Server, SCO
+Unix, Windows NT e Windows 95.
+Su tali piattaforme installiamo, configuriamo e supportiamo pienamente il
+Samba.
+
+Sedac S.a.S. is specialized in the implementation and administration of
+heterogeneous LAN/WAN networks based on SCO Open Server, SCO Unix, Windows
+NT and Windows 95 operating systems.
+On these platforms we fully install, configure and support Samba.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+TREVISO - ITALY
+
+Company: SMC Computers S.r.l.
+Via Roma 4/D
+Lancenigo di Villorba 31020 (TV)
+
+Telephone number: +39-422-608408
+FAX Number : +39-422-608043
+EMail : smc@smc.it
+WWW Address : www.smc.it
+
+Our company is specialized in LAN/WAN connectivity on Unix and
+Windows platforms, RDBMS, Data Warehousing.
+We currently port, install and support Samba on the following
+Unix platforms :
+HP/UX, SunOS 4, SunOS 5, Sinix, Mips, IRIX , AIX, SCO, Linux
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+VICENZA - ITALY
+
+Company: AVnet srl
+Address: via Fogazzaro, 2
+ 36015 SCHIO (VI)
+ ITALY
+phone: 0445/511445
+fax: 0445/511449
+contact: Giovanni Panozzo
+
+e-mail: samba@avnet.it
+
+
+AVnet provides consulting and support on all problems
+regarding unix-to-win networking. We operate as ISP and we
+offer in depth TCP/IP knowledge for lan, intranet and WANs.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+LUXEMBOURG - EUROPE
+
+E.C.C. sa
+11, Rue Bettlange
+L-9657 HARLANGE
+Grand-Duche de Luxembourg
+Tel. +352 93615 (from 09/97: +352 993615)
+Fax +352 93569 (from 09/97: +352 993569)
+oontact person: Stefaan A Eeckels
+email: Stefaan.Eeckels@ecc.lumail
+
+We're located in Luxembourg, and recently provided support
+for Samba at Eurostat (the European Commision), who are using
+Samba to integrate Windows NT workstations in their Solaris
+/ Windows3.1 network. All in all, things run rather smoothly now.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+DELFT - NETHERLANDS
+
+BitWizard B.V.
+van Bronckhorststraat 12
+2612 XV Delft
+The Netherlands
+Tel: +31-15-2137555
+Fax: +31-15-2138217
+Email: samba@BitWizard.nl
+http: http://www.bitwizard.nl/
+
+Specific activities:
+
+ - Linux support
+ - GNU software support
+ - Linux device driver writing
+ - Data recovery
+
+BitWizard supports freely distributable software,
+especially quality products like "Samba".
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+GRONINGEN - THE NETHERLANDS
+
+Company: Le Reseau netwerksystemen BV
+Address: Bieslookstraat 31
+City: Groningen
+Zip: NL-9731 HH
+Country: The Netherlands
+
+We already offer commercial support on Linux and other Unices. Together with
+an application house we have developed a office automation environment which
+heavily depends on Samba. This environment consists of a Linux application
+server which is also the Samba server. A NT server for standard office
+applications. A firewall for Internet connectivity. And a large number of
+DOS/Win3.x/W95 clients that connect to the different machines. User's home
+directories are mounted through Sambe.
+
+We also support other Unices like Solaris, SunOS, HP-UX, Digital Unix and
+AIX.
+
+Sincerely,
+
+Arthur Donkers
+Le Reseau
+
+email : arthur@reseau.nl
+phone : (+31) 595 552431
+URL http://www.reseau.nl
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+NIJMEGEN - THE NETHERLANDS
+
+Xtended Internet (http://www.xtdnet.nl/)
+
+Broerdijk 27 Postbus 170 Tel: 31-24-360 39 19
+6523 GM Nijmegen 6500 AD Nijmegen Fax: 31-24-360 19 99
+The Netherlands The Netherlands info@xtdnet.nl
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+UTRECHT - NETHERLANDS
+
+Van den Hout Creative Communications
+Koos van den Hout
+Email : koos@kzdoos.xs4all.nl
+Phone : +31-30-2871002
+Fax : +31-30-2817051
+Samba experience: Setup and configuration for Linux, Solaris, web
+publishing related usage.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+WROCLAW - POLAND
+
+Name: Sergiusz Pawlowicz
+Institute: Wroclaw University of Technology
+Mail: room 120A, Prusa 53/55, Wroclaw 50-370, Poland
+Tel: +48(71)206450
+Fax: +48(71)212448
+E-mail: ser@pwr.wroc.pl
+WWW: http://www.arch.pwr.wroc.pl/
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+CLUJ - ROMANIA
+
+CompAs Software, Ltd.
+Calea Dorobantilor 38, PO Box 285/1
+3400 Cluj, Romania
+tel: +40-64-431317, +40-64-431327
+fax: +40-64-195239
+
+Contact: Gabriel Juncu (gjuncu@compas.dntcj.ro)
+
+Samba Experience:
+Servers: Linux & Samba 1.9.16 and above
+Clients: MS Client for DOS 3.0, LanMan Client 2.xx,
+ WfW, Windows'95, Windows NT
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+VETLANDA - SWEDEN
+
+ IBS Industridata AB
+ Box 95
+ 574 21 VETLANDA
+ SWEDEN
+
+Phone: +46-383-16065
+Fax: +46-8-287905
+E-mail: samba@ibs.se
+http://www.id.ibs.se/ibsid
+
+We have offices in about 20 cities in Sweden and can provide commercial
+support for Samba.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+BERN - SWITZERLAND
+
+Charles Bueche e-mail : cbueche@worldcom.ch
+Les Morels 9 phone : +41.(0)79.330.00.70
+2515 Preles fax : +41.(0)32.315.52.16
+Switzerland
+
+I have used Samba for more than 4 years across several
+large Swiss companies. I offer support on planing,
+configuration and maintenance of Samba. My primary
+platform is Sun Solaris, but I can also support
+Samba on SunOS, HP, DEC-UNIX, or Linux.
+
+Other duties includes security audits (Inter- & Intranet),
+Sun High Availability and Checkpoint Firewall-1.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+
+
+
+
+MIDDLE EAST
+===========
+
+------------------------------------------------------------------------------
+ISRAEL
+
+Sela Systems
+10 Ha'Kishon St.
+Bnei-Brak
+Israel 51203
+Phone: +972-3-6190999
+Fax: +972-3-6190992
+Email: info@sela.co.il
+
+We have been involved in Samba projects since 1995.
+We have several large-scale clients using Samba in their network
+and getting support from us. We also provide Unix/NT/Novell/Win95
+system and network services and solutions. Our company also provides
+courses and training in many aspects of systems and networking,
+including TCP/IP and Samba.
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
diff --git a/docs/textdocs/Tracing.txt b/docs/textdocs/Tracing.txt
new file mode 100644
index 00000000000..2b724924386
--- /dev/null
+++ b/docs/textdocs/Tracing.txt
@@ -0,0 +1,96 @@
+!==
+!== Tracing.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Andrew Tridgell <samba-bugs@samba.anu.edu.au>
+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-bugs@samba.anu.edu.au)
diff --git a/docs/textdocs/UNIX-SMB.txt b/docs/textdocs/UNIX-SMB.txt
index b2c064215cf..e7fed7fa98f 100644
--- a/docs/textdocs/UNIX-SMB.txt
+++ b/docs/textdocs/UNIX-SMB.txt
@@ -1,3 +1,12 @@
+!==
+!== UNIX-SMB.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Andrew Tridgell <samba-bugs@samba.anu.edu.au>
+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 +15,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 +91,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 +131,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 +144,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 +161,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 +225,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_INSTALL.txt b/docs/textdocs/UNIX_INSTALL.txt
new file mode 100644
index 00000000000..16055d75d0b
--- /dev/null
+++ b/docs/textdocs/UNIX_INSTALL.txt
@@ -0,0 +1,345 @@
+!==
+!== UNIX_INSTALL.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: Andrew Tridgell <samba-bugs@samba.anu.edu.au>
+Date: Unknown
+Status: Current
+Updated: July 5, 1998 <jht@samba.anu.edu.au>
+
+Subject: HOW TO INSTALL AND TEST SAMBA
+===============================================================================
+
+
+STEP 0. Read the man pages. They 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:
+
+ nroff -man smbd.8 | more
+
+Unfortunately, having said this, the man pages are sadly out of date and
+really need more effort to maintain them. Other sources of information
+are pointed to by the Samba web site, http://samba.anu.edu.au/samba.
+
+STEP 1. Building the binaries
+
+To do this, first run the program ./configure in the source
+directory. This should automatically configure Samba for your
+operating system. If you have unusual needs then you may wish to run
+"./configure --help" first to see what special options you can enable.
+
+Then type "make". This will create the binaries.
+
+Once it's successfully compiled you can use "make install" to install
+the binaries and manual pages. You can separately install the binaries
+and/or man pages using "make installbin" and "make installman".
+
+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 "make revert" if you find this version a disaster!
+
+STEP 2. The all important step
+
+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.
+
+If you have installed samba before then you can skip this step.
+
+STEP 3. Create the smb configuration file.
+
+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.
+
+The simplest useful configuration file would be something like this:
+
+ workgroup = MYGROUP
+
+ [homes]
+ guest ok = no
+ read only = no
+
+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 defails)
+
+Note that "make install" will not install a smb.conf file. You need to
+create it yourself. You will also need to create the path you specify
+in the Makefile for the logs etc, such as /usr/local/samba.
+
+Make sure you put the smb.conf file in the same place you specified in
+the Makefile.
+
+For more information about security settings for the [homes] share please
+refer to the document UNIX_SECURITY.txt
+
+STEP 4. Test your config file with testparm
+
+It's important that you test the validity of your smb.conf file using
+the testparm program. If testparm runs OK then it will list the loaded
+services. If not it will give an error message.
+
+Make sure it runs OK and that the services look resonable before
+proceeding.
+
+STEP 5. Starting the smbd and nmbd.
+
+You must choose to start smbd and nmbd either as daemons or from
+inetd. Don't try to do both! Either you can put them in inetd.conf
+and have them started on demand by inetd, or you can start them as
+daemons either from the command line or in /etc/rc.local. 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.
+
+The main advantage of starting smbd and nmbd as a daemon is that they
+will respond slightly more quickly to an initial connection
+request. This is, however, unlilkely to be a problem.
+
+Step 5a. Starting from inetd.conf
+
+NOTE; The following will be different if you use NIS or NIS+ to
+distributed services maps.
+
+Look at your /etc/services. What is defined at port 139/tcp. If
+nothing is defined then add a line like this:
+
+netbios-ssn 139/tcp
+
+similarly for 137/udp you should have an entry like:
+
+netbios-ns 137/udp
+
+Next edit your /etc/inetd.conf and add two lines something like this:
+
+netbios-ssn stream tcp nowait root /usr/local/samba/bin/smbd smbd
+netbios-ns dgram udp wait root /usr/local/samba/bin/nmbd nmbd
+
+The exact syntax of /etc/inetd.conf varies between unixes. Look at the
+other entries in inetd.conf for a guide.
+
+NOTE: Some unixes already have entries like netbios_ns (note the
+underscore) in /etc/services. You must either edit /etc/services or
+/etc/inetd.conf to make them consistant.
+
+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
+ifconfig as root if you don't know what the broadcast is for your
+net. nmbd 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.
+
+!!!WARNING!!! Many unixes only accept around 5 parameters on the
+command line in inetd. This means you shouldn't use spaces between the
+options and arguments, or you should use a script, and start the
+script from inetd.
+
+Restart inetd, perhaps just send it a HUP. If you have installed an
+earlier version of nmbd then you may need to kill nmbd as well.
+
+Step 5b. Alternative: starting it as a daemon
+
+To start the server as a daemon you should create a script something
+like this one, perhaps calling it "startsmb"
+
+#!/bin/sh
+/usr/local/samba/bin/smbd -D
+/usr/local/samba/bin/nmbd -D
+
+then make it executable with "chmod +x startsmb"
+
+You can then run startsmb by hand or execute it from /etc/rc.local
+
+To kill it send a kill signal to the processes nmbd and smbd.
+
+NOTE: If you use the SVR4 style init system then you may like to look
+at the examples/svr4-startup script to make Samba fit into that system.
+
+
+STEP 6. Try listing the shares available on your server
+
+smbclient -L yourhostname
+
+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).
+
+If you choose user level security then you may find that Samba requests
+a password before it will list the shares. See the smbclient docs 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)
+
+STEP 7. try connecting with the unix client. eg:
+
+smbclient '\\yourhostname\aservice'
+
+Typically the "yourhostname" would be the name of the host where you
+installed smbd. The "aservice" is any service you have defined in the
+smb.conf file. Try your user name if you just have a [homes] section
+in smb.conf.
+
+For example if your unix host is bambi and your login name is fred you
+would type:
+
+smbclient '\\bambi\fred'
+
+NOTE: The number of slashes to use depends on the type of shell you
+use. You may need '\\\\bambi\\fred' with some shells.
+
+STEP 8. Try connecting from a dos/WfWg/Win95/NT/os-2 client. Try
+mounting disks. eg:
+
+net use d: \\servername\service
+
+Try printing. eg:
+
+net use lpt1: \\servername\spoolservice
+print filename
+
+Celebrate, or send me a bug report!
+
+WHAT IF IT DOESN'T WORK?
+========================
+
+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.
+
+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.
+
+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.
+
+DIAGNOSING PROBLEMS
+===================
+
+If you have instalation problems then go to DIAGNOSIS.txt to try to
+find the problem.
+
+SCOPE IDs
+=========
+
+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 <scope> 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.
+
+
+CHOOSING THE PROTOCOL LEVEL
+===========================
+
+The SMB protocol has many dialects. Currently Samba supports 5, called
+CORE, COREPLUS, LANMAN1, LANMAN2 and NT1.
+
+You can choose what maximum protocol to support in the smb.conf
+file. The default is NT1 and that is the best for the vast majority of
+sites.
+
+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.
+
+The main advantage of LANMAN2 and NT1 is support for long filenames with some
+clients (eg: smbclient, Windows NT or Win95).
+
+See the smb.conf manual page for more details.
+
+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.
+
+
+PRINTING FROM UNIX TO A CLIENT PC
+=================================
+
+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.
+
+There is also a SYSV style script that does much the same thing called
+smbprint.sysv. It contains instructions.
+
+
+LOCKING
+=======
+
+One area which sometimes causes trouble is locking.
+
+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.
+
+Samba supports "record locking" using the fcntl() unix system
+call. This is often implemented using rpc calls to a rpc.lockd process
+running on the system that owns the filesystem. Unfortunately many
+rpc.lockd implementations are very buggy, particularly when made to
+talk to versions from other vendors. It is not uncommon for the
+rpc.lockd to crash.
+
+There is also a problem translating the 32 bit lock requests generated
+by PC clients to 31 bit requests supported by most
+unixes. Unfortunately many PC applications (typically OLE2
+applications) use byte ranges with the top bit set as semaphore
+sets. Samba attempts translation to support these types of
+applications, and the translation has proved to be quite successful.
+
+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.
+
+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.
+
+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
+compatability modes called DENY_FCB and DENY_DOS.
+
+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).
+
+
+MAPPING USERNAMES
+=================
+
+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.
+
+
+OTHER CHARACTER SETS
+====================
+
+If you have problems using filenames with accented characters in them
+(like the German, French or Scandinavian character sets) then I
+recommmend you look at the "valid chars" option in smb.conf and also
+take a look at the validchars package in the examples directory.
diff --git a/docs/textdocs/UNIX_SECURITY.txt b/docs/textdocs/UNIX_SECURITY.txt
new file mode 100644
index 00000000000..3d9450722fc
--- /dev/null
+++ b/docs/textdocs/UNIX_SECURITY.txt
@@ -0,0 +1,53 @@
+!==
+!== UNIX_SECURITY.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+Contributor: John H Terpstra <jht@samba.anu.edu.au>
+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 :
+
+user = %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..18d383fdb99
--- /dev/null
+++ b/docs/textdocs/Win95.txt
@@ -0,0 +1,77 @@
+!==
+!== Win95.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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..81294206bff 100644
--- a/docs/textdocs/WinNT.txt
+++ b/docs/textdocs/WinNT.txt
@@ -1,6 +1,20 @@
-There are some particular issues with Samba and Windows NT
+!==
+!== WinNT.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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 +22,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 +76,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..aeab46bfcdb
--- /dev/null
+++ b/docs/textdocs/cifsntdomain.txt
@@ -0,0 +1,1501 @@
+!==
+!== cifsntdomain.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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.anu.edu.au/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/security_level.txt b/docs/textdocs/security_level.txt
new file mode 100644
index 00000000000..62953c3516e
--- /dev/null
+++ b/docs/textdocs/security_level.txt
@@ -0,0 +1,99 @@
+!==
+!== security_level.txt for Samba release 2.0.0-alpha6 19 Sep 1998
+!==
+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
+
+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 default
+with samba) 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/examples/README b/examples/README
index 3e58e0faf1c..c2c36bdcdf1 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.anu.edu.au
-Send it to: Andrew.Tridgell@anu.edu.au
diff --git a/examples/autofs/auto.a b/examples/autofs/auto.a
new file mode 100644
index 00000000000..fc293f5391d
--- /dev/null
+++ b/examples/autofs/auto.a
@@ -0,0 +1,18 @@
+# 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,uuname=andreas supra:/aheinrich
+supra_cspiel -fstype=smb,uuname=cspiel supra:/cspiel
+phonon_andreas -fstype=smb,uuname=andreas,fmod=3700 phonon:/andreas
+helium_cspiel -fstype=smb,uuname=cspiel,fmod=3700 helium:/cspiel
+
+#supra_jaz -fstype=smb,user,fmod=644,dmod=755 supra:/f
+
diff --git a/examples/autofs/mount-smb.doc b/examples/autofs/mount-smb.doc
new file mode 100644
index 00000000000..7eee74fce0d
--- /dev/null
+++ b/examples/autofs/mount-smb.doc
@@ -0,0 +1,65 @@
+Date: Tue, 07 Apr 1998
+Contributor: Christoph L. Spiel <Christoph_Spiel@physik.tu-muenchen.de>
+Organization: Munich Institute of Technology, Institute E10
+Subject: WISHES:LINUX:smbmount
+===============================================================================
+Machine Arch: i386
+Machine OS: linux
+Kernel: 2.1.85
+Samba Version: Version 1.9.18p3
+Mount Version: 2.7i
+Autofs Version: 0.3.14
+
+
+Hi SAMBA developers!
+
+I have written a shell script that marries smbmount and mount
+on a Linux-machine with a 2.1.55+ kernel (i.e., a newer developper
+kernel. Especially it makes smbmount compatible
+with autofs! Now, You (when root :-) can say
+ mount -t smb /win-machine/my-share /mntpt
+Concerning the management of the user/password-pairs I have already
+made a step in the right direction, but there is still a lot of
+brain-work to do :-(
+
+The primary problem with the Win passwords
+is that they are under user-control, and not under admin-control
+as the Linux passwords are. Therfore, I give every SAMBA user
+a
+ ~/smb-pass
+file where she can manage her usernames and passwords herself.
+The fundamental mount-tables /etc/fstab and /etc/auto.* only
+list the mount-point and the respective options. The user´s
+password file is adressed via the uuname=<user_name>-option.
+
+An important "side-effect" is that the password file need not to
+be word-readable. In fact my script tests for user-only rights of
+this file to close this potential security-hole.
+
+The script mount.smb has to be installed in /sbin and given mode 755.
+No suid is necessary! I attached an automount table that is currently
+in use on my machine. A user´s password file looks like this:
+
+$ cat ~/smb-pass
+supra:/cspiel cspiel secret
+helium:/c cspiel sesame
+^ ^ ^
+| | +- password
+| +- username
++- share-name as in fundamental mount-table.
+
+It would be nice, if someone else tests my script. Maybe, You have
+already found a better solution than mine. If You find it useful,
+I would be glad to donate it to the SAMBA-project.
+
+BUGS:
+(1) There is no documentation yet. (Yes, I consider this a bug!)
+(2) When used with autofs the automounter overruns mount.smb.
+ This means when accessing an automounted share for the 1st time
+ You may get an empty directory. Retrying several times will
+ cause the mount to complete successfully.
+
+
+Best,
+ Christoph Spiel
+
diff --git a/examples/autofs/mount.smb b/examples/autofs/mount.smb
new file mode 100644
index 00000000000..76f1a596e35
--- /dev/null
+++ b/examples/autofs/mount.smb
@@ -0,0 +1,441 @@
+#!/bin/sh -x
+
+
+# name: mount.smb -- interface between mount and smbmount
+# author: Ch. L. Spiel (cspiel@physik.tu-muenchen.de)
+# $Id: mount.smb,v 1.1 1998/04/13 12:31:10 jht Exp $
+
+# bash version: 1.14.7(1)
+# mount version: 2.7i
+# smbmount version: 1.9.18p3
+
+
+myname=`basename $0`
+passwd_filename="smb-pass" # name of user smb-password file
+lock_file="/var/lock/$myname"
+log_file="/tmp/mount.smb.log"
+
+PATH=/usr/local/samba/bin:/usr/bin:/bin
+
+# check for an existing lock-file quickly(!)
+if [ -e "$lock_file" ]; then
+ # exit, but don´t touch lock-file
+ exit 0
+fi
+# set up new lock-file
+echo > $lock_file
+
+# initialise log-file
+echo "logging of $myname started at `date`" > $log_file
+chmod --silent 600 $log_file
+echo "called with: $@" >> $log_file
+exec >> $log_file 2>&1
+
+
+
+# set default and initial values
+verbose=false # be silent
+fake=false # really do the mount
+fmode="-f 600" # default file mode
+dmode="-d 700" # default dir mode
+
+#uid="-u `id | sed 's/^uid=\([0-9]*\).*$/\1/'`"
+uid="-u 0"
+#gid="-g `id | sed 's/^.*gid=\([0-9]*\).*$/\1/'`"
+gid="-g 0"
+
+
+#
+# functions
+#
+
+# exitproc(int exit_code)
+function exit_proc
+{
+ if [ -n "$lock_file" ]; then
+ # remove current lock-file
+ rm "$lock_file"
+ fi
+ # update log-file
+ echo "" >> $log_file
+ echo "$myname´s return value is $1." >> $log_file
+ echo "logging of $myname ended at `date`." >> $log_file
+ # done.
+ exit $1
+}
+
+
+# split_arg(arg)
+# arg ::= id '=' val
+# set id and val on return
+function split_arg
+{
+ id="$1"
+ val="$2"
+ extra="$3"
+} # end of split_arg
+
+
+# split_passwdline(uline)
+function split_passwdline
+{
+ user_name=$1
+ real_password=$2
+ user_id=$3
+ group_id=$4
+ full_name=$5
+ home_dir=$6
+ shell_name=$7
+}
+
+
+# get_homedir(username)
+function get_homedir
+{
+ local temp_ifs
+
+ temp_ifs="$IFS"
+ uline=`grep "^$1" /etc/passwd`
+ if [ -z "$uline" ]; then
+ echo "$myname: unknown user \"$1\""
+ exit_proc 1
+ fi
+ IFS=":"
+ split_passwdline $uline
+ if [ -z "$home_dir" ]; then
+ echo "$myname: user \"$1\" has no home directory"
+ exit_proc 1
+ fi
+ echo "$home_dir"
+ IFS="$temp_ifs"
+}
+
+
+# get_uid(username)
+function get_uid
+{
+ local temp_ifs
+
+ temp_ifs="$IFS"
+ uline=`grep "^$1" /etc/passwd`
+ if [ -z "$uline" ]; then
+ echo "$myname: unknown user \"$1\""
+ exit_proc 1
+ fi
+ IFS=":"
+ split_passwdline $uline
+ echo "$user_id"
+ IFS="$temp_ifs"
+}
+
+
+# get_gid(username)
+function get_gid
+{
+ local temp_ifs
+
+ temp_ifs="$IFS"
+ uline=`grep "^$1" /etc/passwd`
+ if [ -z "$uline" ]; then
+ echo "$myname: unknown user \"$1\""
+ exit_proc 1
+ fi
+ IFS=":"
+ split_passwdline $uline
+ echo "$group_id"
+ IFS="$temp_ifs"
+}
+
+
+# read_passwd_file(sharename)
+function read_passwd_file
+{
+ local pwd_filename pwd_entry temp_ifs share_name fmod
+
+ pwd_filename=`get_homedir $uuname`/$passwd_filename
+ # use uid and gid of user´s /etc/password entry
+ uid="-u `get_uid $uuname`"
+ gid="-g `get_gid $uuname`"
+ # check existence of password file
+ if [ ! -f "$pwd_filename" -o ! -r "$pwd_filename" ]; then
+ echo "$myname: cannot read from user password file \"$pwd_filename\""
+ exit_proc 1
+ fi
+ # check file permissions
+ for f in $pwd_filename{,~,%,.BAK,.bak,.new,.old,.orig,.sav}; do
+ if [ ! -f $f ]; then continue; fi
+ /bin/ls -l $f | grep -q -- "^-r\(w\|-\)------"
+ if [ $? = 1 ]; then
+ echo "$myname: Found security hole: mode of file \"$f\""
+ echo "$myname: Password file must have permission 400 or 600."
+ echo "$myname: Please fix the file´s mode."
+ exit_proc 1
+ fi
+ done
+
+ share_name="$1" # sharename in smb-format!
+ pwd_entry=`grep -v '^#' "$pwd_filename" | grep -i "^$share_name"`
+ if [ -z "$pwd_entry" ]; then
+ # try uni*-like sharename
+ share_name=`echo $share_name | sed -e 's,^//,,' -e 's,/,:/,'`
+ pwd_entry=`grep -v '^#' "$pwd_filename" | grep -i "^$share_name"`
+ fi
+ if [ -z "$pwd_entry" ]; then
+ # sharename was not found in user´s password file
+ echo "$myname: cannot authentify share named \"$1\" via file \"$pwd_filename\""
+ exit_proc 1
+ fi
+
+ # pwd_entry has the form:
+ # sharename username password
+ temp_ifs="$IFS"
+ IFS=" " # <tab> and <space>
+ split_arg $pwd_entry
+ options="$options -U $val"
+ password="$extra"
+ IFS="$temp_ifs"
+}
+
+
+# process_options(opt1, opt2, ..., optN)
+function process_options
+{
+ local temp_ifs
+
+ for j; do
+ temp_ifs="$IFS" # save current internal-field separator
+ IFS="=" # set new separator
+ split_arg $j # split argument into identifier and value
+ IFS="$temp_ifs" # reset old separator
+ case "$id" in
+ port)
+ options="$options -p $val"
+ ;;
+ debug)
+ options="$options -d $val"
+ ;;
+ log)
+ options="$options -l $val"
+ ;;
+ nbname)
+ options="$options -n $val"
+ ;;
+ nopwd)
+ options="$options -N"
+ ;;
+ maxproto)
+ options="$options -m $val"
+ ;;
+ ip)
+ options="$options -I $val"
+ ;;
+ uname)
+ options="$options -U $val"
+ ;;
+ wrkgrp)
+ options="$options -W $val"
+ ;;
+ term)
+ options="$options -t $val"
+ ;;
+ sdir)
+ options="$options -D $val"
+ ;;
+ pwd)
+ # DO NOT USE THIS OPTION! It is a severe scurity hole.
+ password="$val"
+ ;;
+ uuname)
+ # consult user´s smb-password file
+ uuname="$val" # uni* user name
+ read_passwd_file "$server_service"
+ ;;
+
+ # ignored options
+ async)
+ # do nothing
+ ;;
+ atime)
+ # do nothing
+ ;;
+ auto)
+ # do nothing
+ ;;
+ defaults)
+ # do nothing
+ ;;
+ dev)
+ # do nothing
+ ;;
+ exec)
+ # do nothing
+ ;;
+ noatime)
+ # do nothing
+ ;;
+ noauto)
+ # do nothing
+ ;;
+ nodev)
+ # do nothing
+ ;;
+ noexec)
+ # do nothing
+ ;;
+ nosuid)
+ # do nothing
+ ;;
+ nouser)
+ # do nothing
+ ;;
+ ro)
+ # do nothing
+ ;;
+ rw)
+ # do nothing
+ ;;
+ suid)
+ # do nothing
+ ;;
+ sync)
+ # do nothing
+ ;;
+ user)
+ # do nothing
+ ;;
+
+ # fs options
+ fmod)
+ fmode="-f $val"
+ ;;
+ dmod)
+ dmode="-d $val"
+ ;;
+ uid)
+ uid="-u $val"
+ ;;
+ gid)
+ gid="-g $val"
+ ;;
+
+ # fallthrough
+ *)
+ echo "$myname: unrecognized option $id"
+ exit_proc 1
+ ;;
+ esac
+ done
+} # end of split_options
+
+
+
+#
+# main
+#
+
+
+
+if [ "$verbose" != "false" ]; then
+ # show how we have been called
+ echo "$myname: $*"
+fi
+
+# some checks of the input parameters
+if [ "$#" -lt 2 ]; then
+ echo "$myname: need at least service and mountpoint"
+ exit_proc 1
+fi
+
+if `echo "$2" | grep -vq "^/"`; then
+ echo "$myname: mount point must be an absolut path"
+ exit_proc 1
+fi
+
+
+# copy arguments
+if `echo "$1" | grep -q ":/"`; then
+ # non--standard format, i.e., server:/service
+ server_service=`echo "//$1" | sed -e "sx:/x/x"`
+else
+ # standard format, i.e, //server/service
+ server_service="$1"
+fi
+mntpt="$2"
+
+# copy options
+shift 2 # skip arguments: //server/service and /mnt-point
+for i; do
+ case "$i" in
+ -f | --fake)
+ fake=true
+ ;;
+ -h | --help)
+ echo "usage: mount.smb service [password] mountpoint [options]"
+ exit_proc 0
+ ;;
+ -v | --verbose)
+ verbose=true
+ ;;
+ -V | --version)
+ echo "$myname: mount.smb-0.1.0"
+ exit_proc 0
+ ;;
+ -o)
+ shift # skip leading -o
+ temp_ifs="$IFS" # save current internal-field separator
+ IFS="," # set new separator
+ process_options $*
+ IFS="$temp_ifs" # reset old separator
+ break # mount places options at the end -> we are done
+ ;;
+ *)
+ echo "$myname: unrecognized option $i"
+ exit_proc 1
+ ;;
+ esac
+ shift
+done
+IFS=' '
+
+
+#
+# be careful...
+#
+
+
+# nmblookup server: is node up and running?
+srv=`echo $server_service | sed 's,^//\(.*\)/.*$,\1,'` # server´s name
+nmblookup "$srv" | grep -q "failed to find name"
+if [ "$?" = 0 ]; then
+ echo "$myname: failed to find server \"$srv\"."
+ exit_proc 1
+fi
+
+
+#
+# perform mount
+#
+
+
+fs_options="$fmode $dmode $uid $gid" # all options concerning the mounted fs
+if [ "$verbose" = "true" ]; then
+ # display what we would do. Do not show the password, only show "xxx".
+ echo -n "smbmount $server_service "
+ if [ -n "$password" ]; then # password is set
+ echo -n "xxx " # ... but we don´t show it ;-)
+ fi
+ echo "-c \"mount $mntpt $fs_options\" $options"
+#else
+ # supress further messages
+# exec > /dev/null 2>&1
+#:
+fi
+
+if [ "$fake" != "true" ]; then
+ smbmount $server_service $password -c "mount $mntpt $fs_options" $options
+ echo "smbmount´s exit code was $?."
+fi
+
+# clean up and exit
+exit_proc 0
+
diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus
index b018f3dcce9..584284feb34 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.anu.edu.au/samba/ ~~~~~~~~~~~~~~
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..98c2b72edd2
--- /dev/null
+++ b/examples/printer-accounting/hp5-redir
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+#
+# $Source: /data/src/mirror/cvs/samba/examples/printer-accounting/hp5-redir,v $
+# $Id: hp5-redir,v 1.1 1996/07/23 03:30:56 samba-bugs Exp $
+#
+# 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..3fe45f877fd
--- /dev/null
+++ b/examples/printer-accounting/lp-acct
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# $Source: /data/src/mirror/cvs/samba/examples/printer-accounting/lp-acct,v $
+# $Id: lp-acct,v 1.1 1996/07/23 03:30:56 samba-bugs Exp $
+#
+# 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..079f20aac41 100755
--- a/examples/printing/smbprint
+++ b/examples/printing/smbprint
@@ -53,7 +53,7 @@ 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=\$$#
+eval acct_file=\${$#}
spool_dir=`dirname $acct_file`
config_file=$spool_dir/.config
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..fba4ecca0ac
--- /dev/null
+++ b/examples/smb.conf.default
@@ -0,0 +1,250 @@
+# 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
+ 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..ce159568369
--- /dev/null
+++ b/examples/validchars/validchr.com
Binary files differ
diff --git a/packaging/README b/packaging/README
new file mode 100644
index 00000000000..1adb809ae5a
--- /dev/null
+++ b/packaging/README
@@ -0,0 +1,34 @@
+Copyright (C) 1997 - Samba-Team
+Date: August 19, 1997
+Updates: First Release - 19970819
+===============================================================================
+
+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.
+
+As such, the files contained here are intended for use only by those wishing
+to build their own 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-bugs@samba.anu.edu.au 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/RedHat/README b/packaging/RedHat/README
new file mode 100644
index 00000000000..3b85f5e0a76
--- /dev/null
+++ b/packaging/RedHat/README
@@ -0,0 +1,11 @@
+Preparation Date: Fri Aug 21, 1998
+Preparer: John H Terpstra <jht@samba.anu.edu.au>
+
+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/makefile-path.patch b/packaging/RedHat/makefile-path.patch
new file mode 100644
index 00000000000..b9f5984a782
--- /dev/null
+++ b/packaging/RedHat/makefile-path.patch
@@ -0,0 +1,43 @@
+--- samba-2.0.0/source/Makefile.in.orig Sat Aug 22 02:48:36 1998
++++ samba-2.0.0/source/Makefile.in Fri Aug 21 22:19:32 1998
+@@ -23,11 +23,11 @@
+ .SUFFIXES:
+ .SUFFIXES: .c .o
+
+-BASEDIR=$(prefix)/samba
++BASEDIR= /usr
+ BINDIR = $(BASEDIR)/bin
+-SBINDIR = $(BASEDIR)/bin
+-LIBDIR = $(BASEDIR)/lib
+-VARDIR = $(BASEDIR)/var
++SBINDIR = $(BASEDIR)/sbin
++LIBDIR = /etc
++VARDIR = /var
+ MANDIR = $(BASEDIR)/man
+
+ # The permissions to give the executables
+@@ -36,19 +36,19 @@
+ # 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))
+-SMBLOGFILE = $(VARDIR)/log.smb
+-NMBLOGFILE = $(VARDIR)/log.nmb
++SMBLOGFILE = $(VARDIR)/log/samba/log.smb
++NMBLOGFILE = $(VARDIR)/log/samba/log.nmb
+ CONFIGFILE = $(LIBDIR)/smb.conf
+ LMHOSTSFILE = $(LIBDIR)/lmhosts
+ DRIVERFILE = $(LIBDIR)/printers.def
+ SMB_PASSWD = $(BINDIR)/smbpasswd
+-SMB_PASSWD_FILE = $(BASEDIR)/private/smbpasswd
++SMB_PASSWD_FILE = $(LIBDIR)/smbpasswd
+
+ # This is where SWAT images and help files go
+-SWATDIR = $(BASEDIR)/swat
++SWATDIR = $(BASEDIR)/share/swat
+
+ # the directory where lock files go
+-LOCKDIR = $(VARDIR)/locks
++LOCKDIR = $(VARDIR)/lock/samba
+
+ # The directory where code page definition files go
+ CODEPAGEDIR = $(LIBDIR)/codepages
diff --git a/packaging/RedHat/makerpms.sh.tmpl b/packaging/RedHat/makerpms.sh.tmpl
new file mode 100644
index 00000000000..fa69370dff0
--- /dev/null
+++ b/packaging/RedHat/makerpms.sh.tmpl
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright (C) John H Terpstra 1998
+#
+RPMDIR=`rpm --showrc | awk '/^rpmdir/ { print $3}'`
+SPECDIR=`rpm --showrc | awk '/^specdir/ { print $3}'`
+SRCDIR=`rpm --showrc | awk '/^sourcedir/ { print $3}'`
+
+( cd ../../.. ; tar czvf ${SRCDIR}/samba-PVERSION.tar.gz samba-PVERSION )
+cp -a *.spec $SPECDIR
+cp -a *.patch smb.* samba.log $SRCDIR
+cd $SRCDIR
+chown -R root.root samba-PVERSION
+cd $SPECDIR
+rpm -ba -v samba2.spec
diff --git a/packaging/RedHat/samba.log b/packaging/RedHat/samba.log
new file mode 100644
index 00000000000..c5f2a5b45bc
--- /dev/null
+++ b/packaging/RedHat/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/RedHat/samba.pamd b/packaging/RedHat/samba.pamd
new file mode 100644
index 00000000000..f38e70184af
--- /dev/null
+++ b/packaging/RedHat/samba.pamd
@@ -0,0 +1,2 @@
+auth required /lib/security/pam_pwdb.so nullok shadow
+account required /lib/security/pam_pwdb.so
diff --git a/packaging/RedHat/samba2.spec.tmpl b/packaging/RedHat/samba2.spec.tmpl
new file mode 100644
index 00000000000..cc6e8bc33ca
--- /dev/null
+++ b/packaging/RedHat/samba2.spec.tmpl
@@ -0,0 +1,274 @@
+Summary: Samba SMB client and server
+Name: samba
+Version: PVERSION
+Release: PRELEASE
+Copyright: GNU GPL version 2
+Group: Networking
+Source: ftp://samba.anu.edu.au/pub/samba/samba-PVERSION.tar.gz
+Patch: makefile-path.patch
+Packager: John H Terpstra [Samba-Team] <jht@samba.anu.edu.au>
+Requires: pam >= 0.64
+BuildRoot: /tmp/samba
+
+%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.
+
+This a work in progress release only. This is NOT a production
+stable release and it is VERY VERY pre-alpha.
+
+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
+* Fri Aug 21 1998 John H Terpstra <jht@samba.anu.edu.au>
+ - Updated for Samba version 2.0 building
+
+* Sat Jul 4 1998 John H Terpstra <jht@samba.anu.edu.au>
+ - fixed codepage preservation during update via -Uvh
+
+* Sun Apr 26 1998 John H Terpstra <jht@samba.anu.edu.au>
+ - Tidy up for early alpha releases
+ - added findsmb from SGI packaging
+
+* Thu Apr 9 1998 John H Terpstra <jht@samba.anu.edu.au>
+ - Updated spec file
+ - Included new codepage.936
+
+* Sat Mar 20 1998 John H Terpstra <jht@samba.anu.edu/au>
+ - Added swat facility
+
+* Sat Jan 24 1998 John H Terpstra <jht@samba.anu.edu.au>
+ - 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
+./configure
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/etc/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/home/samba
+mkdir -p $RPM_BUILD_ROOT/usr/{bin,sbin}
+mkdir -p $RPM_BUILD_ROOT/usr/share/swat/{images,help,include}
+mkdir -p $RPM_BUILD_ROOT/usr/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 smbrun smbstatus testparm testprns \
+ make_smbcodepage make_printerdef
+do
+install -m755 -s source/bin/$i $RPM_BUILD_ROOT/usr/bin
+done
+for i in addtosmbpass mksmbpasswd.sh smbtar
+do
+install -m755 source/script/$i $RPM_BUILD_ROOT/usr/bin
+done
+
+# Install secure binary files
+for i in smbd nmbd swat
+do
+install -m755 -s source/bin/$i $RPM_BUILD_ROOT/usr/sbin
+done
+
+# Install level 1 man pages
+for i in smbclient.1 smbrun.1 smbstatus.1 smbtar.1 testparm.1 testprns.1 make_smbcodepage.1
+do
+install -m644 docs/$i $RPM_BUILD_ROOT/usr/man/man1
+done
+
+# Install codepage source files
+for i in 437 737 850 852 861 866 932 936 949 950
+do
+install -m644 source/codepages/codepage_def.$i $RPM_BUILD_ROOT/etc/codepages/src
+done
+
+# Install SWAT helper files
+for i in swat/help/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT/usr/share/swat/help
+done
+for i in swat/images/*.{jpg,gif}
+do
+install -m644 $i $RPM_BUILD_ROOT/usr/share/swat/images
+done
+for i in swat/include/*.html
+do
+install -m644 $i $RPM_BUILD_ROOT/usr/share/swat/include
+done
+
+# Install the miscellany
+install -m644 swat/README $RPM_BUILD_ROOT/usr/share/swat
+install -m644 docs/smb.conf.5 $RPM_BUILD_ROOT/usr/man/man5
+install -m644 docs/samba.7 $RPM_BUILD_ROOT/usr/man/man7
+install -m644 docs/smbd.8 $RPM_BUILD_ROOT/usr/man/man8
+install -m644 docs/nmbd.8 $RPM_BUILD_ROOT/usr/man/man8
+install -m644 docs/smbpasswd.8 $RPM_BUILD_ROOT/usr/man/man8
+install -m644 packaging/RedHat/smb.conf $RPM_BUILD_ROOT/etc/smb.conf
+install -m644 packaging/RedHat/smbusers $RPM_BUILD_ROOT/etc/smbusers
+install -m755 packaging/RedHat/smbprint $RPM_BUILD_ROOT/usr/bin
+install -m755 packaging/RedHat/findsmb $RPM_BUILD_ROOT/usr/bin
+install -m755 packaging/RedHat/smbadduser $RPM_BUILD_ROOT/usr/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/usr/sbin/samba
+install -m644 packaging/RedHat/samba.pamd $RPM_BUILD_ROOT/etc/pam.d/samba
+install -m644 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
+/usr/bin/make_smbcodepage c $i /etc/codepages/src/codepage_def.$i /etc/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 /usr/sbin/swat swat' >> /etc/inetd.conf
+killall -1 inetd
+fi
+
+
+%preun
+/sbin/chkconfig --del smb
+
+%postun
+if [ -x /etc/pam.d/samba ]; then
+ rm -f /etc/pam.d/samba
+fi
+if [ -e /etc/codepages ]; then
+ rm -rf /etc/codepages
+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
+
+%files
+%doc README COPYING Manifest Read-Manifest-Now
+%doc WHATSNEW.txt Roadmap
+%doc docs
+%doc swat/README
+%doc examples
+%attr(-,root,root) /usr/sbin/smbd
+%attr(-,root,root) /usr/sbin/nmbd
+%attr(-,root,root) /usr/sbin/swat
+%attr(755,root,root) /usr/sbin/samba
+%attr(-,root,root) /usr/bin/addtosmbpass
+%attr(-,root,root) /usr/bin/mksmbpasswd.sh
+%attr(-,root,root) /usr/bin/smbclient
+%attr(-,root,root) /usr/bin/testparm
+%attr(-,root,root) /usr/bin/testprns
+%attr(-,root,root) /usr/bin/smbrun
+%attr(-,root,root) /usr/bin/findsmb
+%attr(-,root,root) /usr/bin/smbstatus
+%attr(-,root,root) /usr/bin/nmblookup
+%attr(-,root,root) /usr/bin/make_smbcodepage
+%attr(-,root,root) /usr/bin/make_printerdef
+%attr(-,root,root) /usr/bin/smbpasswd
+%attr(-,root,root) /usr/bin/smbtar
+%attr(-,root,root) /usr/bin/smbprint
+%attr(-,root,root) /usr/bin/smbadduser
+%attr(-,root,root) /usr/share/swat/help/parameters.html
+%attr(-,root,root) /usr/share/swat/help/welcome.html
+%attr(-,root,root) /usr/share/swat/images/background.jpg
+%attr(-,root,root) /usr/share/swat/images/background.gif
+%attr(-,root,root) /usr/share/swat/images/globals.gif
+%attr(-,root,root) /usr/share/swat/images/home.gif
+%attr(-,root,root) /usr/share/swat/images/printers.gif
+%attr(-,root,root) /usr/share/swat/images/shares.gif
+%attr(-,root,root) /usr/share/swat/images/samba.gif
+%attr(-,root,root) /usr/share/swat/images/status.gif
+%attr(-,root,root) /usr/share/swat/images/viewconfig.gif
+%attr(-,root,root) /usr/share/swat/include/header.html
+%attr(-,root,root) /usr/share/swat/include/footer.html
+%attr(-,root,root) %config /etc/lmhosts
+%attr(-,root,root) %config /etc/smb.conf
+%attr(-,root,root) %config /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) /etc/codepages/src/codepage_def.437
+%attr(-,root,root) /etc/codepages/src/codepage_def.737
+%attr(-,root,root) /etc/codepages/src/codepage_def.850
+%attr(-,root,root) /etc/codepages/src/codepage_def.852
+%attr(-,root,root) /etc/codepages/src/codepage_def.861
+%attr(-,root,root) /etc/codepages/src/codepage_def.866
+%attr(-,root,root) /etc/codepages/src/codepage_def.932
+%attr(-,root,root) /etc/codepages/src/codepage_def.936
+%attr(-,root,root) /etc/codepages/src/codepage_def.949
+%attr(-,root,root) /etc/codepages/src/codepage_def.950
+%attr(-,root,root) /usr/man/man1/smbstatus.1
+%attr(-,root,root) /usr/man/man1/smbclient.1
+%attr(-,root,root) /usr/man/man1/make_smbcodepage.1
+%attr(-,root,root) /usr/man/man1/smbrun.1
+%attr(-,root,root) /usr/man/man1/smbtar.1
+%attr(-,root,root) /usr/man/man1/testparm.1
+%attr(-,root,root) /usr/man/man1/testprns.1
+%attr(-,root,root) /usr/man/man5/smb.conf.5
+%attr(-,root,root) /usr/man/man7/samba.7
+%attr(-,root,root) /usr/man/man8/smbd.8
+%attr(-,root,root) /usr/man/man8/nmbd.8
+%attr(-,root,root) /usr/man/man8/smbpasswd.8
+%attr(-,root,nobody) %dir /home/samba
+%attr(-,root,root) %dir /etc/codepages
+%attr(-,root,root) %dir /etc/codepages/src
+%attr(-,root,root) %dir /var/lock/samba
+%attr(-,root,root) %dir /var/log/samba
+%attr(777,root,root) %dir /var/spool/samba
diff --git a/packaging/RedHat/smb.conf b/packaging/RedHat/smb.conf
new file mode 100644
index 00000000000..1e5b920b11e
--- /dev/null
+++ b/packaging/RedHat/smb.conf
@@ -0,0 +1,281 @@
+# 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
+
+# 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
+
+# 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/RedHat/smb.init b/packaging/RedHat/smb.init
new file mode 100755
index 00000000000..6529977d236
--- /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/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/smbadduser b/packaging/RedHat/smbadduser
new file mode 100755
index 00000000000..2f38bf28f1a
--- /dev/null
+++ b/packaging/RedHat/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/RedHat/smbprint b/packaging/RedHat/smbprint
new file mode 100755
index 00000000000..51b15706add
--- /dev/null
+++ b/packaging/RedHat/smbprint
@@ -0,0 +1,77 @@
+#!/bin/sh -x
+
+# 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..c10efbf22a7
--- /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..f071e1809b9
--- /dev/null
+++ b/packaging/SGI/idb.pl
@@ -0,0 +1,262 @@
+#!/usr/bin/perl
+require "pwd.pl" || die "Required pwd.pl not found";
+
+# This perl script automatically generates the samba.idb file
+
+&initpwd;
+$curdir = $ENV{"PWD"};
+
+# We don't want the files listed in .cvsignore in the source tree
+open(IGNORES,"../../source/.cvsignore") || die "Unable to open .cvsignore file\n";
+while (<IGNORES>) {
+ chop;
+ $ignores{$_}++;
+}
+close IGNORES;
+
+# get the names of all the binary files to be installed
+open(MAKEFILE,"../../source/Makefile") || die "Unable to open Makefile\n";
+@makefile = <MAKEFILE>;
+@sprogs = grep(/^SPROGS /,@makefile);
+@progs1 = grep(/^PROGS1 /,@makefile);
+@progs = grep(/^PROGS /,@makefile);
+@scripts = grep(/^SCRIPTS /,@makefile);
+@codepage = grep(/^CODEPAGELIST/,@makefile);
+close MAKEFILE;
+
+if (@sprogs) {
+ @sprogs[0] =~ s/^.*\=//;
+ @sprogs = split(' ',@sprogs[0]);
+}
+if (@progs) {
+ @progs[0] =~ s/^.*\=//;
+ @progs = split(' ',@progs[0]);
+}
+if (@progs1) {
+ @progs1[0] =~ s/^.*\=//;
+ @progs1 = split(' ',@progs1[0]);
+}
+if (@scripts) {
+ @scripts[0] =~ s/^.*\=//;
+ @scripts = split(' ',@scripts[0]);
+}
+if (@codepage) {
+ @codepage[0] =~ s/^.*\=//;
+ chdir '../../source';
+ # if we have codepages we need to create them for the package
+ system("chmod +x ./script/installcp.sh");
+ system("./script/installcp.sh . . ../packaging/SGI/codepages ./bin @codepage[0]");
+ chdir $curdir;
+ @codepage = sort split(' ',@codepage[0]);
+}
+# install the swat files
+chdir '../../source';
+system("chmod +x ./script/installswat.sh");
+system("./script/installswat.sh ../packaging/SGI/swat ./");
+system("cp ../swat/README ../packaging/SGI/swat");
+chdir $curdir;
+
+# add my local files to the list of binaries to install
+@bins = sort byfilename (@sprogs,@progs,@progs1,@scripts,("/findsmb","/sambalp","/smbprint"));
+
+# get a complete list of all files in the tree
+chdir '../../';
+&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);
+
+@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$/ & !/^packaging\/SGI\/bins/ & !/^packaging\/SGI\/catman/ & !/^packaging\/SGI\/html/ & !/^packaging\/SGI\/codepages/ & !/^packaging\/SGI\/swat/, @allfiles);
+
+open(IDB,">samba.idb") || die "Unable to open samba.idb for output\n";
+
+print IDB "f 0644 root sys etc/config/samba packaging/SGI/samba.config samba.sw.base config(update)\n";
+print IDB "f 0755 root sys etc/init.d/samba packaging/SGI/samba.rc samba.sw.base\n";
+print IDB "l 0000 root sys etc/rc0.d/K39samba packaging/SGI samba.sw.base symval(../init.d/samba)\n";
+print IDB "l 0000 root sys etc/rc2.d/S81samba packaging/SGI samba.sw.base symval(../init.d/samba)\n";
+
+@copyfile = grep (/^COPY/,@allfiles);
+print IDB "d 0755 root sys usr/relnotes/samba/ packaging/SGI samba.man.relnotes\n";
+print IDB "f 0644 root sys usr/relnotes/samba/@copyfile[0] @copyfile[0] samba.man.relnotes\n";
+print IDB "f 0644 root sys usr/relnotes/samba/legal_notice.html packaging/SGI/legal_notice.html samba.man.relnotes\n";
+print IDB "f 0644 root sys usr/relnotes/samba/samba-relnotes.html packaging/SGI/relnotes.html samba.man.relnotes\n";
+
+print IDB "d 0755 root sys usr/samba/ packaging/SGI samba.sw.base\n";
+print IDB "f 0444 root sys usr/samba/README packaging/SGI/README samba.sw.base\n";
+
+print IDB "d 0755 root sys usr/samba/bin/ packaging/SGI samba.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 source/$nextfile samba.sw.base\n";
+ }
+ elsif ($filename eq "findsmb") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename packaging/SGI/$filename samba.sw.base\n";
+ }
+ elsif ($filename eq "swat") {
+ print IDB "f 4755 root sys usr/samba/bin/$filename source/$nextfile samba.sw.base\n";
+ }
+ elsif ($filename eq "sambalp") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename packaging/SGI/$filename samba.sw.base\n";
+ }
+ elsif ($filename eq "smbprint") {
+ print IDB "f 0755 root sys usr/samba/bin/$filename packaging/SGI/$filename samba.sw.base\n";
+ }
+ else {
+ print IDB "f 0755 root sys usr/samba/bin/$filename source/$nextfile samba.sw.base\n";
+ }
+ }
+}
+
+print IDB "d 0755 root sys usr/samba/docs/ docs samba.man.doc\n";
+while (@docs) {
+ $nextfile = shift @docs;
+ next if ($nextfile eq "CVS");
+ ($junk,$file) = split(/\//,$nextfile,2);
+ if (grep(/\/$/,$nextfile)) {
+ print IDB "d 0755 root sys usr/samba/docs/$file $nextfile samba.man.doc\n";
+ }
+ else {
+ print IDB "f 0644 root sys usr/samba/docs/$file $nextfile samba.man.doc\n";
+ }
+}
+
+print IDB "f 0755 root sys usr/samba/inetd.sh packaging/SGI/inetd.sh samba.sw.base\n";
+print IDB "d 0755 root sys usr/samba/lib/ packaging/SGI samba.sw.base\n";
+if (@codepage) {
+ print IDB "d 0755 root sys usr/samba/lib/codepages packaging/SGI samba.sw.base\n";
+ while (@codepage) {
+ $nextpage = shift @codepage;
+ print IDB "f 0644 root sys usr/samba/lib/codepages/codepage.$nextpage packaging/SGI/codepages/codepage.$nextpage samba.sw.base\n";
+ }
+}
+print IDB "f 0644 root sys usr/samba/lib/smb.conf packaging/SGI/smb.conf samba.sw.base config(update)\n";
+print IDB "f 0755 root sys usr/samba/mkprintcap.sh packaging/SGI/mkprintcap.sh samba.sw.base\n";
+
+print IDB "d 0644 root sys usr/samba/private/ packaging/SGI samba.sw.base\n";
+print IDB "f 0600 root sys usr/samba/private/smbpasswd packaging/SGI/smbpasswd samba.sw.base config(update)\n";
+print IDB "d 0755 root sys usr/samba/src/ packaging/SGI samba.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)) {
+ print IDB "d 0755 root sys usr/samba/src/$nextfile $nextfile samba.src.samba\n";
+ }
+ else {
+ if (grep((/\.sh$/ | /\.pl$/ | /mkman$/),$nextfile)) {
+ print IDB "f 0755 root sys usr/samba/src/$nextfile $nextfile samba.src.samba\n";
+ }
+ else {
+ print IDB "f 0644 root sys usr/samba/src/$nextfile $nextfile samba.src.samba\n";
+ }
+ }
+}
+
+print IDB "f 0755 root sys usr/samba/startswat.sh packaging/SGI/startswat.sh samba.sw.base\n";
+print IDB "d 0755 root sys usr/samba/swat/ packaging/SGI/swat samba.sw.base\n";
+while (@swatfiles) {
+ $nextfile = shift @swatfiles;
+ ($file = $nextfile) =~ s/^packaging\/SGI\/swat\///;
+ next if !$file;
+ if (grep(/\/$/,$file)) {
+ print IDB "d 0755 root sys usr/samba/swat/$file packaging/SGI/swat/$file samba.sw.base\n";
+ }
+ else {
+ print IDB "f 0444 root sys usr/samba/swat/$file packaging/SGI/swat/$file samba.sw.base\n";
+ }
+}
+
+print IDB "d 0755 root sys usr/samba/var/ packaging/SGI samba.sw.base\n";
+print IDB "d 0755 root sys usr/samba/var/locks/ packaging/SGI samba.sw.base\n";
+
+print IDB "d 0755 root sys usr/share/catman/u_man/ packaging/SGI samba.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 packaging/SGI samba.man.manpages\n";
+ $olddirnum = $dirnum;
+ }
+ print IDB "f 0664 root sys usr/share/catman/u_man/cat$dirnum/$file $nextfile samba.man.manpages\n";
+}
+
+close IDB;
+print "\n\nsamba.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 $dir";
+ 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;
+ }
+}
diff --git a/packaging/SGI/inetd.sh b/packaging/SGI/inetd.sh
new file mode 100755
index 00000000000..8c4c6cb8d8b
--- /dev/null
+++ b/packaging/SGI/inetd.sh
@@ -0,0 +1,29 @@
+#! /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.O
+sed -e "/^netbios/D" -e "/^#SAMBA/D" /etc/inetd.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
+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/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/makefile.pl b/packaging/SGI/makefile.pl
new file mode 100755
index 00000000000..d621097a227
--- /dev/null
+++ b/packaging/SGI/makefile.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+
+# This perl script creates the SGI specific Makefile.
+# The BASEDIR is set to /usr/samba, MANDIR is set to /usr/share/man, and
+# the lines are uncommented for the requested OS version. If no version
+# is specified, IRIX 6 is used.
+
+if (!@ARGV) {
+ $OSver = "6";
+}
+else {
+ $OSver = $ARGV[0];
+}
+
+open(MAKEIN,"../../source/Makefile") || die "Unable to open source Makefile\n";
+open(MAKEOUT,">Makefile") || die "Unable to open Makefile for output\n";
+while (<MAKEIN>) {
+ if (/^BASEDIR =/) {
+ print MAKEOUT "BASEDIR = /usr/samba\n";
+ }
+ elsif (/^MANDIR =/) {
+ print MAKEOUT "MANDIR = /usr/share/man\n";
+ }
+ elsif (/^# FOR SGI IRIX $OSver/) {
+ print MAKEOUT;
+ while (<MAKEIN>) {
+ last if ($_ eq "\n");
+ if (/^# (FLAGSM|LIBSM|FLAGS1)/) {
+ s/^# //;
+ }
+ print MAKEOUT;
+ }
+ print MAKEOUT;
+ }
+ else {
+ print MAKEOUT;
+ }
+}
diff --git a/packaging/SGI/mkman b/packaging/SGI/mkman
new file mode 100755
index 00000000000..4f14fafcdce
--- /dev/null
+++ b/packaging/SGI/mkman
@@ -0,0 +1,27 @@
+#!/bin/sh
+# if you wish to make html versions of the man pages then add the
+# argument html when calling this script. You must have rman installed.
+#
+
+if [ ! -d catman ]; then
+ mkdir catman
+fi
+
+if [ "$1" = "html" ]; then
+ if [ ! -d html ]; then
+ mkdir html
+ fi
+fi
+
+
+FILES="*.?"
+
+cd ../../docs
+for FILE in $FILES ; do
+ neqn $FILE | tbl | nroff -man > ../packaging/SGI/catman/`basename $FILE`
+ compress -f ../packaging/SGI/catman/`basename $FILE`
+ if [ "$1" = "html" ]; then
+ rman -f html -r "%s.%s.html" $FILE > ../packaging/SGI/html/$FILE.html
+ fi
+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..d298095ae9e
--- /dev/null
+++ b/packaging/SGI/mkrelease.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# This file goes through all the necessary steps to build a release package.
+# You may specify a OS major version number (4, 5, or 6) to specify which
+# OS release to build. If no version number is given it will default to 6.
+
+doclean=""
+
+if [ "$1" = "clean" ]; then
+ doclean=$1
+ shift
+fi
+
+if [ "$doclean" = "clean" ]; then
+ cd ../../source
+ make distclean
+ cd ../packaging/SGI
+ rm -rf bins catman html codepages swat samba.idb samba.spec
+fi
+
+# create the catman versions of the manual pages
+#
+echo Making manual pages
+./mkman
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat making manual pages\n";
+ exit $errstat;
+fi
+
+cd ../../source
+echo Create SGI specific Makefile
+./configure --prefix=/usr --mandir=/usr/src/man
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat creating Makefile\n";
+ exit $errstat;
+fi
+
+
+# build the sources
+#
+echo Making binaries
+
+if [ "$1" = "5" ]; then
+ make "CFLAGS=-O -g3" all
+else
+ make "CFLAGS=-O -g3 -n32" all
+fi
+
+errstat=$?
+if [ $errstat -ne 0 ]; then
+ echo "Error $errstat building sources\n";
+ exit $errstat;
+fi
+
+cd ../packaging/SGI
+
+# 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..7477d28c27d
--- /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.anu.edu.au/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.anu.edu.au">listproc@samba.anu.edu.au</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.anu.edu.au">samba@samba.anu.edu.au</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.anu.edu.au">listproc@samba.anu.edu.au</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.anu.edu.au/pub/samba/">http://samba.anu.edu.au/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/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..121b3400a38
--- /dev/null
+++ b/packaging/SGI/samba.rc
@@ -0,0 +1,42 @@
+#! /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
+ ;;
+*)
+ 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..fd0cef8f933
--- /dev/null
+++ b/packaging/SGI/sambalp
@@ -0,0 +1,150 @@
+#!/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");
+}
+
+# Remove the file only if it lives in /usr/tmp, /tmp, or /var/tmp.
+unlink($file) if $file =~ m=^(/(usr|var))?/tmp=;
diff --git a/packaging/SGI/smb.conf b/packaging/SGI/smb.conf
new file mode 100644
index 00000000000..b7cbae63d15
--- /dev/null
+++ b/packaging/SGI/smb.conf
@@ -0,0 +1,122 @@
+; 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
+;
+; 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
+
+ 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 and "share modes=yes"
+; if you want to support the file sharing modes for multiple users
+; of the same files
+ locking = yes
+ lock directory = /usr/samba/var/locks
+ share modes = yes
+
+; 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
+
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+; To allow Win95 clients to automatically load printer drivers, uncomment
+; the following section (and the lines in the printers section below).
+; Run the make_printerdef command to create the /usr/samba/lib/printers.def
+; file (see the PRINTER_DRIVER.txt file in the docs directory for info).
+; Copy all the required files to the /usr/samba/printer directory
+;
+;[printer$]
+; comment = printer driver directory
+; path=/usr/samba/printer
+; public=yes
+; writable=no
+; browseable=yes
+
+[printers]
+ comment = All Printers
+ path = /usr/tmp
+ browseable = no
+ printable = yes
+ public = yes
+ writable = no
+ create mask = 0700
+;
+; this specifies the location of the share containing the printer driver
+; files - see the printer$ section above
+;
+; printer driver location = \\%h\printer$
+;
+; the following line will make all printers default to the QMS-PS 810 Turbo
+; driver - which works quite well for Impressario. If you need a diferent
+; driver for a specific printer, create a section for that printer and
+; specify the correct printer driver.
+;
+; printer driver = QMS-PS 810 Turbo
+
+
+[tmp]
+ comment = Temporary file space
+ path = /usr/tmp
+ read only = no
+ public = yes
diff --git a/packaging/SGI/smbpasswd b/packaging/SGI/smbpasswd
new file mode 100644
index 00000000000..79c834dc354
--- /dev/null
+++ b/packaging/SGI/smbpasswd
@@ -0,0 +1 @@
+username:uid:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:Long name:user home dir:user shell
diff --git a/packaging/SGI/smbprint b/packaging/SGI/smbprint
new file mode 100644
index 00000000000..0db8b6f7e3a
--- /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 -P > /dev/null
+exit $?
+
diff --git a/packaging/SGI/spec.pl b/packaging/SGI/spec.pl
new file mode 100755
index 00000000000..3bd643eef6e
--- /dev/null
+++ b/packaging/SGI/spec.pl
@@ -0,0 +1,87 @@
+#!/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 (/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..c2fc9fb467d
--- /dev/null
+++ b/packaging/SGI/startswat.sh
@@ -0,0 +1,21 @@
+#! /bin/sh
+#
+# add SWAT deamon to inetd.conf
+#
+cp /etc/inetd.conf /etc/inetd.O
+sed -e "/^swat/D" -e "/^#SWAT/D" /etc/inetd.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
+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/pkg-specs/Packaging.script b/packaging/Solaris/pkg-specs/Packaging.script
new file mode 100644
index 00000000000..6f182c33e52
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/Packaging.script
@@ -0,0 +1,5 @@
+#!/bin/sh
+./mkprototype
+pkgmk -o -d /tmp -b `pwd` -f ./prototype
+cd /tmp
+pkgtrans . samba.pkg samba
diff --git a/packaging/Solaris/pkg-specs/mkprototype b/packaging/Solaris/pkg-specs/mkprototype
new file mode 100644
index 00000000000..5ca0746beea
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/mkprototype
@@ -0,0 +1,31 @@
+#!/bin/sh
+# this creates prototype files
+pkgproto * > prototype
+nawk 'BEGIN { print "# d directory"
+ print "# e a file to be edited upon installation or removal"
+ print "# f a standard executable or data file"
+ print "# i installation script or information file"
+ print "# l linked file"
+ print "# s symbolic link"
+ print "# v volatile file (one whose contents are expected to
+change)"
+ print "#" }
+/ pkginfo / { print "i pkginfo" ; next }
+/ postinstall / { print "i postinstall" ; next }
+/ postremove / { print "i postremove" ; next }
+/d none usr / { print "d none usr ? ? ?" ; next }
+/d none usr\/local / { print "d none usr/local ? ? ?" ; next }
+/d none etc / { print "d none etc ? ? ?" ; next }
+/f none etc\// { $1 = "v" }
+/d none opt / { print "d none opt ? ? ?" ; next }
+/d none var / { print "d none var ? ? ?" ; next }
+/none prototype / { next }
+/none mkprototype / { next }
+/ src[ \/]/ { next }
+/^[dfv]/ { $5 = "bin"
+ $6 = "bin"
+ print
+ next }
+{ print }' prototype >/tmp/prototype.$$
+mv /tmp/prototype.$$ prototype
+
diff --git a/packaging/Solaris/pkg-specs/pkginfo b/packaging/Solaris/pkg-specs/pkginfo
new file mode 100644
index 00000000000..ab06b3fffab
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/pkginfo
@@ -0,0 +1,12 @@
+PSTAMP=Mon Sep 29 17:26:14 BST 1997
+PKG=samba
+NAME=SMB based file/printer sharing
+VERSION=1.9.17p2,REV=1
+ARCH=sparc
+CATEGORY=system
+VENDOR=samba group
+DESC=File and printer sharing for NT workstations
+CLASSES=none
+INTONLY=1
+HOTLINE=Please contact your local UNIX support group
+BASEDIR=/
diff --git a/packaging/Solaris/pkg-specs/postinstall b/packaging/Solaris/pkg-specs/postinstall
new file mode 100644
index 00000000000..0fbe9da10b5
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/postinstall
@@ -0,0 +1,37 @@
+#!/bin/sh
+# install samba
+
+nawk '/^netbios-[ns]*[ ]/ {next}
+{print}
+END { print "netbios-ssn 139/tcp"
+ print "netbios-ns 137/udp # samba service" }' \
+ ${PKG_INSTALL_ROOT}/etc/inet/services > /tmp/services.$$ && \
+ mv -f /tmp/services.$$ ${PKG_INSTALL_ROOT}/etc/inet/services &&
+\
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/services && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/services"
+
+nawk '/samba.*mbd[ ]/ { next }
+{print}
+END { print "# samba connections are handled by smbd and nmbd"
+ print "netbios-ssn stream tcp nowait root /opt/samba/bin/smbd
+smbd"
+ print "netbios-ns dgram udp wait root /opt/samba/bin/nmbd nmbd" }'
+\
+ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf > /tmp/inetd.conf.$$ &&
+\
+ mv -f /tmp/inetd.conf.$$ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf
+&& \
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf"
+
+echo "Installed samba service into ${PKG_INSTALL_ROOT:-/}"
+
+inetpid=`/bin/ps -ef | awk '/ \/usr\/sbin\/inetd / { print $2 } '`
+if [ "X$inetpid" = "X" ]; then
+ echo "inetd not running"
+else
+ echo "Restarting inetd($inetpid)"
+ kill -HUP $inetpid
+fi
+
diff --git a/packaging/Solaris/pkg-specs/postremove b/packaging/Solaris/pkg-specs/postremove
new file mode 100644
index 00000000000..7f7a5c1f8e4
--- /dev/null
+++ b/packaging/Solaris/pkg-specs/postremove
@@ -0,0 +1,30 @@
+#!/bin/sh
+# remove samba
+
+nawk '/^netbios-[ns]*[ ]/ {next}
+{print} ' \
+ ${PKG_INSTALL_ROOT}/etc/inet/services > /tmp/services.$$ && \
+ mv -f /tmp/services.$$ ${PKG_INSTALL_ROOT}/etc/inet/services &&
+\
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/services && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/services"
+
+nawk '/samba.*mbd[ ]/ { next }
+{print} ' \
+ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf > /tmp/inetd.conf.$$ &&
+\
+ mv -f /tmp/inetd.conf.$$ ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf
+&& \
+ chmod 644 ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf && \
+ echo "Updated ${PKG_INSTALL_ROOT}/etc/inet/inetd.conf"
+
+echo "Removed samba service from ${PKG_INSTALL_ROOT:-/}"
+
+inetpid=`/bin/ps -ef | awk '/ \/usr\/sbin\/inetd / { print $2 } '`
+if [ "X$inetpid" = "X" ]; then
+ echo "inetd not running"
+else
+ echo "Restarting inetd($inetpid)"
+ kill -HUP $inetpid
+fi
+
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..637af1781e1
--- /dev/null
+++ b/packaging/SuSE/5.2/samba.spec
@@ -0,0 +1,122 @@
+#
+# 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/smbrun
+/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.
+* 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 .
+Documentation: /usr/doc/packages/samba
+
diff --git a/source/.cvsignore b/source/.cvsignore
new file mode 100644
index 00000000000..f68f2c23838
--- /dev/null
+++ b/source/.cvsignore
@@ -0,0 +1,34 @@
+.deps
+Makefile
+Makefile.RPM
+config
+config.cache
+config.h
+config.log
+config.status
+cvs.log
+d2
+make_printerdef
+make_smbcodepage
+makefile
+makefile.sunos5
+memcheck.awk
+nmbd
+nmblookup
+nmfns.txt
+nmlist.txt
+nmused.txt
+notes.txt
+smbclient
+smbd
+smbpasswd
+smbrun
+smbstatus
+smbtorture
+swat
+testparm
+testprns
+text.txt
+unused.txt
+wsmbconf
+wsmbstatus
diff --git a/source/Makefile.in b/source/Makefile.in
new file mode 100644
index 00000000000..ff69a5e641a
--- /dev/null
+++ b/source/Makefile.in
@@ -0,0 +1,445 @@
+###########################################################################
+# Makefile.in for Samba - rewritten for autoconf support
+# Copyright Andrew Tridgell 1992-1998
+###########################################################################
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+mandir=@mandir@
+INSTALL_BIN=$(exec_prefix)/bin
+INSTALL_MAN=$(prefix)/man
+
+LIBS=@LIBS@
+CC=@CC@
+CFLAGS=@CFLAGS@
+LDFLAGS=@LDFLAGS@
+AWK=@AWK@
+
+INSTALLCMD=@INSTALL@
+
+VPATH=@srcdir@
+srcdir=@srcdir@
+SHELL=/bin/sh
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+BASEDIR=$(prefix)/samba
+BINDIR = $(BASEDIR)/bin
+SBINDIR = $(BASEDIR)/bin
+LIBDIR = $(BASEDIR)/lib
+VARDIR = $(BASEDIR)/var
+MANDIR = $(BASEDIR)/man
+
+# 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))
+SMBLOGFILE = $(VARDIR)/log.smb
+NMBLOGFILE = $(VARDIR)/log.nmb
+CONFIGFILE = $(LIBDIR)/smb.conf
+LMHOSTSFILE = $(LIBDIR)/lmhosts
+DRIVERFILE = $(LIBDIR)/printers.def
+SMB_PASSWD = $(BINDIR)/smbpasswd
+SMB_PASSWD_FILE = $(BASEDIR)/private/smbpasswd
+
+# This is where SWAT images and help files go
+SWATDIR = $(BASEDIR)/swat
+
+# the directory where lock files go
+LOCKDIR = $(VARDIR)/locks
+
+# The directory where code page definition files go
+CODEPAGEDIR = $(LIBDIR)/codepages
+
+# The current codepage definition list.
+CODEPAGELIST= 437 737 850 852 861 932 866 949 950 936
+
+# where you are going to have the smbrun binary. This defaults to the
+# install directory. This binary is needed for correct printing
+# and magic script execution. This should be an absolute path!
+# Also not that this should include the name "smbrun" on the end (the
+# name of the executable)
+SMBRUN = $(BINDIR)/smbrun
+
+
+PASSWD_FLAGS = -DSMB_PASSWD=\"$(SMB_PASSWD)\" -DSMB_PASSWD_FILE=\"$(SMB_PASSWD_FILE)\"
+FLAGS1 = $(CFLAGS) -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx -DSMBLOGFILE=\"$(SMBLOGFILE)\" -DNMBLOGFILE=\"$(NMBLOGFILE)\"
+FLAGS2 = -DCONFIGFILE=\"$(CONFIGFILE)\" -DLMHOSTSFILE=\"$(LMHOSTSFILE)\"
+FLAGS3 = -DSWATDIR=\"$(SWATDIR)\" -DSBINDIR=\"$(SBINDIR)\" -DLOCKDIR=\"$(LOCKDIR)\" -DSMBRUN=\"$(SMBRUN)\" -DCODEPAGEDIR=\"$(CODEPAGEDIR)\"
+FLAGS4 = -DDRIVERFILE=\"$(DRIVERFILE)\"
+FLAGS5 = $(FLAGS1) $(FLAGS2) $(FLAGS3) $(FLAGS4) -DHAVE_INCLUDES_H
+FLAGS = $(FLAGS5) $(PASSWD_FLAGS)
+
+SPROGS = bin/smbd bin/nmbd bin/swat
+PROGS1 = bin/smbclient bin/testparm bin/testprns bin/smbrun bin/smbstatus
+PROGS2 = bin/rpcclient bin/smbpasswd bin/make_smbcodepage
+MPROGS = @MPROGS@
+PROGS = $(PROGS1) $(PROGS2) $(MPROGS) bin/nmblookup bin/make_printerdef
+
+SCRIPTS = script/smbtar script/addtosmbpass
+
+
+######################################################################
+# object file lists
+######################################################################
+
+LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \
+ lib/getsmbpass.o lib/interface.o lib/kanji.o lib/md4.o \
+ lib/membuffer.o lib/netmask.o lib/pidfile.o lib/replace.o \
+ lib/signal.o lib/slprintf.o lib/system.o lib/time.o lib/ufc.o \
+ lib/util.o lib/genrand.o lib/username.o lib/access.o lib/smbrun.o \
+ lib/bitmap.o
+
+UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
+ ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o
+
+PARAM_OBJ = param/loadparm.o param/params.o
+
+LIBSMB_OBJ = libsmb/clientgen.o libsmb/namequery.o libsmb/nmblib.o \
+ libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o \
+ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o
+
+RPC_SERVER_OBJ = rpc_server/srv_ldap_helpers.o rpc_server/srv_lsa.o \
+ rpc_server/srv_lsa_hnd.o rpc_server/srv_netlog.o \
+ rpc_server/srv_pipe_hnd.o rpc_server/srv_reg.o \
+ rpc_server/srv_samr.o rpc_server/srv_srvsvc.o \
+ rpc_server/srv_util.o rpc_server/srv_wkssvc.o
+
+RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_misc.o \
+ rpc_parse/parse_net.o rpc_parse/parse_prs.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_CLIENT_OBJ = rpc_client/cli_login.o rpc_client/cli_netlogon.o \
+ rpc_client/cli_pipe.o rpc_client/cli_lsarpc.o \
+ rpc_client/cli_wkssvc.o rpc_client/cli_samr.o
+
+LOCKING_OBJ = locking/locking.o locking/locking_shm.o locking/locking_slow.o \
+ locking/shmem.o locking/shmem_sysv.o
+
+PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o \
+ passdb/pass_check.o passdb/ldap.o passdb/nispass.o
+
+SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
+ smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \
+ smbd/ipc.o smbd/mangle.o smbd/negprot.o \
+ smbd/message.o smbd/nttrans.o smbd/pipes.o smbd/predict.o \
+ smbd/quotas.o smbd/reply.o smbd/ssl.o smbd/trans2.o smbd/uid.o \
+ smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o smbd/blocking.o \
+ smbd/process.o smbd/oplock.o smbd/service.o smbd/error.o
+
+PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/printing.o
+
+SMBD_OBJ = $(SMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
+ $(RPC_SERVER_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \
+ $(LOCKING_OBJ) $(PASSDB_OBJ) $(PRINTING_OBJ) $(LIB_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) \
+ $(PASSDB_OBJ) $(LIB_OBJ)
+
+SWAT_OBJ = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
+ web/swat.o $(LIBSMB_OBJ) $(LOCKING_OBJ) \
+ $(PARAM_OBJ) $(PASSDB_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+SMBRUN_OBJ = utils/smbrun.o
+
+MAKE_SMBCODEPAGE_OBJ = utils/make_smbcodepage.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) $(LIB_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) \
+ $(UBIQX_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) $(LIB_OBJ)
+
+RPCCLIENT_OBJ = rpcclient/rpcclient.o \
+ rpcclient/display.o \
+ rpcclient/cmd_lsarpc.o \
+ rpcclient/cmd_wkssvc.o \
+ rpcclient/cmd_samr.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
+ $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ)
+# rpcclient/cmd_netlogon.o \
+# rpcclient/cmd_srvsvc.o
+
+CLIENT_OBJ = client/client.o client/clientutil.o client/clitar.o \
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
+
+MOUNT_OBJ = client/smbmount.o client/clientutil.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 = utils/torture.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
+ $(UBIQX_OBJ) $(LIB_OBJ)
+
+PROTO_OBJ = $(SMBD_OBJ) $(NMBD_OBJ) $(SWAT_OBJ) $(CLIENT_OBJ) $(RPCCLIENT_OBJ)
+
+######################################################################
+# now the rules...
+######################################################################
+
+all : CHECK $(SPROGS) $(PROGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .o .h
+
+CHECK:
+ @echo "Using FLAGS = $(FLAGS)"
+ @echo "Using LIBS = $(LIBS)"
+ @(cd $(srcdir) && ls -1d */*.c && echo bin/.) | \
+ sed 's,/[^/]*$$,,;s,^$$,.,' | \
+ while read dir; do \
+ if test ! -d "$$dir"; then \
+ echo mkdir "$$dir" && mkdir "$$dir" || true; \
+ else true; fi; \
+ done
+
+.c.o: @MAINT@ .deps/.dummy obj-dirs
+ @echo Compiling $*.c
+ @dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` && \
+ if test ! -d "$$dir"; then \
+ echo mkdir "$$dir" && mkdir "$$dir" || true; \
+ else true; fi
+ @$(CC) -I. -I$(srcdir) $(FLAGS) -c $< -o $@ \
+ @MAINT@ -Wp,-MD,.deps/`echo $* | sed s,/,_,g`.P && : >.deps/.stamp
+# the line above is for atomatic dependency tracking
+# it will only work with GNU make, gcc and --enable-maintainer-mode
+
+MKDIR_BIN = if test ! -d bin; then echo mkdir bin && mkdir bin || true; else true; fi
+
+bin/smbd: $(SMBD_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/nmbd: $(NMBD_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(NMBD_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/swat: $(SWAT_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(SWAT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbrun: $(SMBRUN_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(SMBRUN_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/rpcclient: $(RPCCLIENT_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(RPCCLIENT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbclient: $(CLIENT_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(CLIENT_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbmount: $(MOUNT_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(MOUNT_OBJ) $(LIBS)
+
+bin/smbmnt: $(MNT_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(MNT_OBJ) $(LIBS)
+
+bin/smbumount: $(UMOUNT_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(UMOUNT_OBJ) $(LIBS)
+
+bin/testparm: $(TESTPARM_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(TESTPARM_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/testprns: $(TESTPRNS_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(TESTPRNS_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbstatus: $(STATUS_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(STATUS_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbpasswd: $(SMBPASSWD_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(SMBPASSWD_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/make_smbcodepage: $(MAKE_SMBCODEPAGE_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(MAKE_SMBCODEPAGE_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/nmblookup: $(NMBLOOKUP_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(NMBLOOKUP_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/make_printerdef: $(MAKE_PRINTERDEF_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(MAKE_PRINTERDEF_OBJ) $(LDFLAGS) $(LIBS)
+
+bin/smbtorture: $(SMBTORTURE_OBJ)
+ @echo Linking $@
+ @$(MKDIR_BIN)
+ @$(CC) $(FLAGS) -o $@ $(SMBTORTURE_OBJ) $(LDFLAGS) $(LIBS)
+
+
+install: installbin installman installscripts installcp installswat
+
+installdirs:
+ $(SHELL) $(srcdir)/install-sh -d -m $(INSTALLPERMS) \
+ $(BASEDIR) $(SBINDIR) $(BINDIR) $(LIBDIR) $(VARDIR) $(CODEPAGEDIR)
+
+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)
+
+installcp: installdirs
+ @$(SHELL) $(srcdir)/script/installcp.sh $(srcdir) $(LIBDIR) $(CODEPAGEDIR) $(BINDIR) $(CODEPAGELIST)
+
+installswat: installdirs
+ @$(SHELL) $(srcdir)/script/installswat.sh $(SWATDIR) $(srcdir)
+
+# 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)
+
+uninstall: uninstallman uninstallbin uninstallscripts uninstallcp
+
+uninstallman:
+ @$(SHELL) $(srcdir)/script/uninstallman.sh $(MANDIR) $(srcdir)
+
+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)
+
+uninstallcp:
+ @$(SHELL) $(srcdir)/script/uninstallcp.sh $(CODEPAGEDIR) $(CODEPAGELIST)
+
+clean:
+ -rm -f core */*~ *~ */*.o
+
+proto:
+ @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 | grep -v "ubiqx/"` > include/proto.h
+
+etags:
+ etags `find . -name "*.[ch]"`
+
+ctags:
+ ctags `find . -name "*.[ch]"`
+
+realclean: clean
+ -rm -f config.log $(PROGS) $(SPROGS)
+
+distclean: realclean
+ -rm -f include/config.h include/stamp-h Makefile
+ -rm -f config.status config.cache
+ -rm -rf .deps
+
+# 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
+
+# Rules for maintainers (--enable-maintainer-mode)
+AUTOCONF=@AUTOCONF@
+AUTOHEADER=@AUTOHEADER@
+
+# when configure.in is updated, reconfigure
+$(srcdir)/configure: @MAINT@ $(srcdir)/configure.in $(srcdir)/aclocal.m4
+ cd $(srcdir) && $(AUTOCONF)
+
+config.status: $(srcdir)/configure
+ $(SHELL) ./config.status --recheck
+
+Makefile: $(srcdir)/Makefile.in config.status \
+ include/stamp-h # just to ensure that config.h is up-to-date
+ CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# note that nothing depends on config.h, so will probably be rebuilt
+# only when explicitly requested
+include/config.h: include/stamp-h
+ @:
+
+include/stamp-h: $(srcdir)/include/config.h.in config.status
+ CONFIG_FILES= CONFIG_HEADERS=include/config.h $(SHELL) ./config.status
+ @echo > include/stamp-h
+
+$(srcdir)/include/config.h.in: $(srcdir)/include/stamp-h.in
+ @:
+
+$(srcdir)/include/stamp-h.in: @MAINT@ $(srcdir)/acconfig.h $(srcdir)/configure.in
+ cd $(srcdir) && $(AUTOHEADER)
+ @date -u > $@
+
+# automatic dependency tracking rules
+.deps/.dummy:
+ @-if test ! -d .deps; then rm -rf .deps; mkdir .deps; fi
+ @: >$@
+
+.deps/.stamp: .deps/.dummy
+ @:
+
+.deps/.P: .deps/.stamp
+ @-cat .deps/*.P >$@ 2>/dev/null
+
+@MAINT@-include .deps/.P
diff --git a/source/acconfig.h b/source/acconfig.h
new file mode 100644
index 00000000000..2c6361bf498
--- /dev/null
+++ b/source/acconfig.h
@@ -0,0 +1,71 @@
+#undef HAVE_BROKEN_READDIR
+#undef HAVE_ERRNO_DECL
+#undef HAVE_LONGLONG
+#undef HAVE_OFF64_T
+#undef HAVE_REMSH
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UTIMBUF
+#undef ssize_t
+#undef ino_t
+#undef ssize_t
+#undef HAVE_CONNECT
+#undef HAVE_SHORT_INO_T
+#undef WITH_AFS
+#undef WITH_DFS
+#undef SUNOS5
+#undef SUNOS4
+#undef LINUX
+#undef AIX
+#undef IRIX
+#undef HPUX
+#undef QNX
+#undef SCO
+#undef OSF1
+#undef NEXT2
+#undef HAVE_SHARED_MMAP
+#undef HAVE_SYSV_IPC
+#undef HAVE_FCNTL_LOCK
+#undef HAVE_FTRUNCATE_EXTEND
+#undef HAVE_TRAPDOOR_UID
+#undef HAVE_ROOT
+#undef HAVE_UNION_SEMUN
+#undef HAVE_NETMASK_IFCONF
+#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_NETMASK_IFREQ
+#undef HAVE_NETMASK_AIX
+#undef HAVE_CRYPT
+#undef WITH_MMAP
+#undef WITH_SYSLOG
+#undef WITH_SSL
+#undef WITH_LDAP
+#undef WITH_NISPLUS
+#undef WITH_NISPLUS_HOME
+#undef WITH_AUTOMOUNT
+#undef WITH_SMBMOUNT
+#undef HAVE_PAM_AUTHENTICATE
+#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 HAVE_INO64_T
+#undef HAVE_STRUCT_FLOCK64
+#undef SIZEOF_INO_T
+#undef SIZEOF_OFF_T
+#undef STAT_STATVFS64
+#undef HAVE_LIBREADLINE
+#undef HAVE_KERNEL_OPLOCKS
+#undef HAVE_IRIX_SPECIFIC_CAPABILITIES
+#undef KRB4_AUTH
diff --git a/source/aclocal.m4 b/source/aclocal.m4
new file mode 100644
index 00000000000..95737958889
--- /dev/null
+++ b/source/aclocal.m4
@@ -0,0 +1,36 @@
+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 based on Automake's maintainer mode
+AC_DEFUN(SAMBA_MAINTAINER_MODE,[
+ AC_ARG_ENABLE(maintainer-mode,
+ [ --enable-maintainer-mode enable some make rules for maintainers],
+ maint_mode=$enableval, maint_mode=no)
+ if test x"$maint_mode" = x"yes"; then MAINT=; else MAINT='#'; fi
+ AC_SUBST(MAINT)
+ AC_PATH_PROG(AUTOCONF, autoconf, autoconf)
+ AC_SUBST(AUTOCONF)
+ AC_PATH_PROG(AUTOHEADER, autoheader, autoheader)
+ AC_SUBST(AUTOHEADER)
+])
diff --git a/source/architecture.doc b/source/architecture.doc
new file mode 100644
index 00000000000..ff0fcefb868
--- /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 message 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/pass_check.c b/source/auth/pass_check.c
new file mode 100644
index 00000000000..d847407bbb4
--- /dev/null
+++ b/source/auth/pass_check.c
@@ -0,0 +1,915 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* 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 HAVE_PAM
+/*******************************************************************
+check on PAM authentication
+********************************************************************/
+
+/* We first need some helper functions */
+#include <security/pam_appl.h>
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static char *PAM_username;
+static char *PAM_password;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int 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;
+
+ #define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) return PAM_CONV_ERR;
+
+ 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(PAM_username);
+ /* PAM frees resp */
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(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... */
+ free (reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply) *resp = reply;
+ return PAM_SUCCESS;
+}
+static struct pam_conv PAM_conversation = {
+ &PAM_conv,
+ NULL
+};
+
+
+static BOOL pam_auth(char *user,char *password)
+{
+ pam_handle_t *pamh;
+ int pam_error;
+
+ /* Now use PAM to do authentication. For now, we won't worry about
+ * session logging, only authentication. Bail out if there are any
+ * errors. Since this is a limited protocol, and an even more limited
+ * function within a server speaking this protocol, we can't be as
+ * verbose as would otherwise make sense.
+ * Query: should we be using PAM_SILENT to shut PAM up?
+ */
+ #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
+ pam_end(pamh, 0); return False; \
+ }
+ PAM_password = password;
+ PAM_username = user;
+ pam_error = pam_start("samba", user, &PAM_conversation, &pamh);
+ PAM_BAIL;
+/* Setting PAM_SILENT stops generation of error messages to syslog
+ * to enable debugging on Red Hat Linux set:
+ * /etc/pam.d/samba:
+ * auth required /lib/security/pam_pwdb.so nullok shadow audit
+ * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
+ */
+ pam_error = pam_authenticate(pamh, PAM_SILENT);
+ PAM_BAIL;
+ /* It is not clear to me that account management is the right thing
+ * to do, but it is not clear that it isn't, either. This can be
+ * removed if no account management should be done. Alternately,
+ * put a pam_allow.so entry in /etc/pam.conf for account handling. */
+ pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
+ PAM_BAIL;
+ pam_end(pamh, PAM_SUCCESS);
+ /* If this point is reached, the user has been authenticated. */
+ return(True);
+}
+#endif
+
+
+#ifdef WITH_AFS
+/*******************************************************************
+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);
+ }
+ return(False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+/*****************************************************************
+ 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];
+
+ 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 become_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.
+ */
+
+ if (setregid(-1, pw->pw_gid) != 0) {
+ DEBUG(0,("Can't set egid to %d (%s)\n",
+ pw->pw_gid, strerror(errno)));
+ return False;
+ }
+
+ if (setreuid(-1, pw->pw_uid) != 0) {
+ setgid(0);
+ DEBUG(0,("Can't set euid to %d (%s)\n",
+ pw->pw_uid, strerror(errno)));
+ return False;
+ }
+
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
+
+ return(False);
+ }
+
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
+ user,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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
+
+ return(False);
+ }
+
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ 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));
+
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ return(False);
+ }
+
+ DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
+ user, 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
+
+ return(False);
+ }
+
+ setuid(0);
+ setgid(0);
+
+ DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
+
+ 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 KRB5_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb5_auth(char *user,char *password)
+{
+ krb5_data tgtname = {
+ 0,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME
+ };
+ krb5_context kcontext;
+ krb5_principal kprinc;
+ krb5_principal server;
+ krb5_creds kcreds;
+ int options = 0;
+ krb5_address **addrs = (krb5_address **)0;
+ krb5_preauthtype *preauth = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_timestamp now;
+ krb5_ccache ccache = NULL;
+ int retval;
+ char *name;
+
+ if (retval=krb5_init_context(&kcontext)) {
+ return(False);
+ }
+
+ if (retval = krb5_timeofday(kcontext, &now)) {
+ return(False);
+ }
+
+ if (retval = krb5_cc_default(kcontext, &ccache)) {
+ return(False);
+ }
+
+ if (retval = krb5_parse_name(kcontext, user, &kprinc)) {
+ return(False);
+ }
+
+ ZERO_STRUCT(kcreds);
+
+ kcreds.client = kprinc;
+
+ if ((retval = krb5_build_principal_ext(kcontext, &server,
+ krb5_princ_realm(kcontext, kprinc)->length,
+ krb5_princ_realm(kcontext, kprinc)->data,
+ tgtname.length,
+ tgtname.data,
+ krb5_princ_realm(kcontext, kprinc)->length,
+ krb5_princ_realm(kcontext, kprinc)->data,
+ 0))) {
+ return(False);
+ }
+
+ kcreds.server = server;
+
+ retval = krb5_get_in_tkt_with_password(kcontext,
+ options,
+ addrs,
+ NULL,
+ preauth,
+ password,
+ 0,
+ &kcreds,
+ 0);
+
+ if (retval) {
+ return(False);
+ }
+
+ return(True);
+}
+#endif /* KRB5_AUTH */
+
+#ifdef KRB4_AUTH
+#include <krb.h>
+
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb4_auth(char *user,char *password)
+{
+ char realm[REALM_SZ];
+ char tkfile[MAXPATHLEN];
+
+ if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+ (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
+ }
+
+ (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
+ (int)getpid());
+
+ krb_set_tkt_string(tkfile);
+ if (krb_verify_user(user, "", realm,
+ password, 0,
+ "rmcd") == KSUCCESS) {
+ unlink(tkfile);
+ return 1;
+ }
+ unlink(tkfile);
+ return 0;
+}
+#endif /* KRB4_AUTH */
+
+#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);
+
+ 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 BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
+{
+ int len = strlen(s);
+ int i;
+
+#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 (string_combinations2(s,i+1,fn,N-1))
+ return(True);
+ s[i] = c;
+ }
+ return(False);
+}
+
+/****************************************************************************
+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)(char *),int N)
+{
+ int n;
+ for (n=1;n<=N;n++)
+ if (string_combinations2(s,0,fn,n)) return(True);
+ return(False);
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static BOOL password_check(char *password)
+{
+
+#ifdef HAVE_PAM
+ /* This falls through if the password check fails
+ - if HAVE_CRYPT is not defined this causes an error msg
+ saying Warning - no crypt available
+ - if HAVE_CRYPT is defined this is a potential security hole
+ as it may authenticate via the crypt call when PAM
+ settings say it should fail.
+ if (pam_auth(user,password)) return(True);
+ Hence we make a direct return to avoid a second chance!!!
+ */
+ return (pam_auth(this_user,password));
+#endif
+
+#ifdef WITH_AFS
+ if (afs_auth(this_user,password)) return(True);
+#endif
+
+#ifdef WITH_DFS
+ if (dfs_auth(this_user,password)) return(True);
+#endif
+
+#ifdef KRB5_AUTH
+ if (krb5_auth(this_user,password)) return(True);
+#endif
+
+#ifdef KRB4_AUTH
+ if (krb4_auth(this_user,password)) return(True);
+#endif
+
+#ifdef OSF1_ENH_SEC
+ {
+ BOOL 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);
+ }
+ return ret;
+ }
+#endif
+
+#ifdef ULTRIX_AUTH
+ return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
+#endif
+
+#ifdef LINUX_BIGCRYPT
+ return(linux_bigcrypt(password,this_salt,this_crypted));
+#endif
+
+#ifdef HAVE_BIGCRYPT
+ return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
+#endif
+
+#ifndef HAVE_CRYPT
+ DEBUG(1,("Warning - no crypt available\n"));
+ return(False);
+#else
+ return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
+#endif
+}
+
+
+
+/****************************************************************************
+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 True on correct match, False otherwise
+****************************************************************************/
+BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
+ BOOL (*fn)(char *, char *))
+{
+ pstring pass2;
+ int level = lp_passwordlevel();
+ struct passwd *pass;
+
+ if (password) password[pwlen] = 0;
+
+#if DEBUG_PASSWORD
+ 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);
+ }
+
+
+ DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
+
+ if (!pass) {
+ DEBUG(3,("Couldn't find user %s\n",user));
+ return(False);
+ }
+
+#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) {
+ 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)
+ 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,("No entry for user %s in protected database !\n",
+ user));
+ return(False);
+ }
+ }
+#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_user,pass->pw_name);
+ fstrcpy(this_salt,pass->pw_passwd);
+ /* crypt on some platforms (HPUX in particular)
+ won't work with more than 2 salt characters. */
+ this_salt[2] = 0;
+
+ fstrcpy(this_crypted,pass->pw_passwd);
+
+ if (!*this_crypted) {
+ if (!lp_null_passwords()) {
+ DEBUG(2,("Disallowing %s with null password\n",
+ this_user));
+ return(False);
+ }
+ if (!*password) {
+ DEBUG(3,("Allowing access to %s with null password\n",
+ this_user));
+ return(True);
+ }
+ }
+
+ /* try it as it came to us */
+ if (password_check(password)) {
+ if (fn) fn(user,password);
+ 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)) {
+ if (fn) fn(user,password);
+ return(True);
+ }
+
+ /* give up? */
+ if (level < 1) {
+
+ /* restore it */
+ fstrcpy(password,pass2);
+
+ return(False);
+ }
+
+ /* last chance - all combinations of up to level chars upper! */
+ strlower(password);
+
+ if (string_combinations(password,password_check,level)) {
+ if (fn) fn(user,password);
+ return(True);
+ }
+
+ /* restore it */
+ fstrcpy(password,pass2);
+
+ return(False);
+}
diff --git a/source/bin/.cvsignore b/source/bin/.cvsignore
new file mode 100644
index 00000000000..0038aca110c
--- /dev/null
+++ b/source/bin/.cvsignore
@@ -0,0 +1,14 @@
+make_printerdef
+make_smbcodepage
+nmbd
+nmblookup
+smbclient
+smbd
+smbpasswd
+smbrun
+smbstatus
+smbtorture
+swat
+testparm
+testprns
+rpcclient
diff --git a/source/change-log b/source/change-log
index e120ac6f02a..42a27fe6f68 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.anu.edu.au.
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..0d27039cb93 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
SMB client
- 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
@@ -19,12 +19,9 @@
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
@@ -32,23 +29,28 @@
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;
+extern BOOL in_client;
+extern pstring service;
+extern pstring desthost;
+extern pstring global_myname;
+extern pstring myhostname;
+extern pstring password;
+extern pstring username;
+extern pstring workgroup;
+char *cmdstr="";
+extern BOOL got_pass;
+extern BOOL no_pass;
+extern BOOL connect_as_printer;
+extern BOOL connect_as_ipc;
+extern struct in_addr ipzero;
+
+extern BOOL doencrypt;
extern pstring user_socket_options;
+static int process_tok(fstring tok);
+static void cmd_help(char *dum_in, char *dum_out);
+
/* 30 second timeout on most commands */
#define CLIENT_TIMEOUT (30*1000)
#define SHORT_TIMEOUT (5*1000)
@@ -56,42 +58,42 @@ extern pstring user_socket_options;
/* value for unused fid field in trans2 secondary request */
#define FID_UNUSED (0xFFFF)
-int name_type = 0x20;
+extern int name_type;
-int max_protocol = PROTOCOL_NT1;
+extern int max_protocol;
time_t newer_than = 0;
int archive_level = 0;
-extern struct in_addr myip;
-
extern pstring debugf;
extern int DEBUGLEVEL;
BOOL translation = False;
+extern int cnum;
+extern int mid;
+extern int pid;
+extern int tid;
+extern int gid;
+extern int uid;
+
+extern BOOL have_ip;
+extern int max_xmit;
+
+static int interpret_long_filename(int level,char *p,file_info *finfo);
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo);
+static int interpret_short_filename(char *p,file_info *finfo);
+static BOOL do_this_one(file_info *finfo);
+
/* 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;
+mode_t myumask = 0755;
extern pstring scope;
@@ -102,8 +104,6 @@ int printmode = 1;
BOOL recurse = False;
BOOL lowercase = False;
-BOOL have_ip = False;
-
struct in_addr dest_ip;
#define SEPARATORS " \t\n\r"
@@ -112,8 +112,8 @@ BOOL abort_mget = True;
extern int Protocol;
-BOOL readbraw_supported = False;
-BOOL writebraw_supported = False;
+extern BOOL readbraw_supported ;
+extern BOOL writebraw_supported;
pstring fileselection = "";
@@ -125,60 +125,35 @@ int get_total_time_ms = 0;
int put_total_size = 0;
int put_total_time_ms = 0;
+/* totals globals */
+int dir_total = 0;
extern int Client;
#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);
-
+#define CNV_LANG(s) dos_to_unix(s,False)
+#define CNV_INPUT(s) unix_to_dos(s,True)
/****************************************************************************
-setup basics in a outgoing packet
+send an SMBclose on an SMB file handle
****************************************************************************/
-void setup_pkt(char *outbuf)
+static void cli_smb_close(char *inbuf, char *outbuf, int clnt_fd, int c_num, int f_num)
{
- 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);
- }
+ bzero(outbuf,smb_size);
+ set_message(outbuf,3,0,True);
+
+ CVAL (outbuf,smb_com) = SMBclose;
+ SSVAL(outbuf,smb_tid,c_num);
+ cli_setup_pkt(outbuf);
+ SSVAL (outbuf,smb_vwv0, f_num);
+ SIVALS(outbuf,smb_vwv1, -1);
+
+ send_smb(clnt_fd, outbuf);
+ client_receive_smb(clnt_fd,inbuf,CLIENT_TIMEOUT);
}
+
/****************************************************************************
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.
@@ -234,7 +209,8 @@ static int readfile(char *b, int size, int n, FILE *f)
n++;
}
- b[i++] = c;
+ if(i < n)
+ b[i++] = c;
}
return(i);
@@ -267,7 +243,7 @@ static BOOL chkpath(char *path,BOOL report)
pstring inbuf,outbuf;
char *p;
- strcpy(path2,path);
+ fstrcpy(path2,path);
trim_string(path2,NULL,"\\");
if (!*path2) *path2 = '\\';
@@ -275,14 +251,26 @@ static BOOL chkpath(char *path,BOOL report)
set_message(outbuf,0,4 + strlen(path2),True);
SCVAL(outbuf,smb_com,SMBchkpth);
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,path2);
+ fstrcpy(p,path2);
+
+#if 0
+ {
+ /* this little bit of code can be used to extract NT error codes.
+ Just feed a bunch of "cd foo" commands to smbclient then watch
+ in netmon (tridge) */
+ static int code=0;
+ SIVAL(outbuf, smb_rcls, code | 0xC0000000);
+ SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
+ code++;
+ }
+#endif
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (report && CVAL(inbuf,smb_rcls) != 0)
DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
@@ -309,10 +297,10 @@ static void send_message(char *inbuf,char *outbuf)
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,username);
+ pstrcpy(p,username);
p = skip_string(p,1);
*p++ = 4;
- strcpy(p,desthost);
+ pstrcpy(p,desthost);
p = skip_string(p,1);
set_message(outbuf,0,PTR_DIFF(p,smb_buf(outbuf)),False);
@@ -320,7 +308,7 @@ static void send_message(char *inbuf,char *outbuf)
send_smb(Client,outbuf);
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
+ if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
{
printf("SMBsendstrt failed. (%s)\n",smb_errstr(inbuf));
return;
@@ -360,7 +348,7 @@ static void send_message(char *inbuf,char *outbuf)
send_smb(Client,outbuf);
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
+ if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
{
printf("SMBsendtxt failed (%s)\n",smb_errstr(inbuf));
return;
@@ -383,7 +371,7 @@ static void send_message(char *inbuf,char *outbuf)
send_smb(Client,outbuf);
- if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
+ if (!client_receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
{
printf("SMBsendend failed (%s)\n",smb_errstr(inbuf));
return;
@@ -403,10 +391,10 @@ static void do_dskattr(void)
set_message(outbuf,0,0,True);
CVAL(outbuf,smb_com) = SMBdskattr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
DEBUG(0,("Error in dskattr: %s\n",smb_errstr(inbuf)));
@@ -420,7 +408,7 @@ static void do_dskattr(void)
/****************************************************************************
show cd/pwd
****************************************************************************/
-static void cmd_pwd(void)
+static void cmd_pwd(char *dum_in, char *dum_out)
{
DEBUG(0,("Current directory is %s",CNV_LANG(service)));
DEBUG(0,("%s\n",CNV_LANG(cur_dir)));
@@ -436,26 +424,28 @@ static void do_cd(char *newdir)
pstring saved_dir;
pstring dname;
+ dos_format(newdir);
+
/* Save the current directory in case the
new directory is invalid */
- strcpy(saved_dir, cur_dir);
+ pstrcpy(saved_dir, cur_dir);
if (*p == '\\')
- strcpy(cur_dir,p);
+ pstrcpy(cur_dir,p);
else
- strcat(cur_dir,p);
+ pstrcat(cur_dir,p);
if (*(cur_dir+strlen(cur_dir)-1) != '\\') {
- strcat(cur_dir, "\\");
+ pstrcat(cur_dir, "\\");
}
dos_clean_name(cur_dir);
- strcpy(dname,cur_dir);
- strcat(cur_dir,"\\");
+ pstrcpy(dname,cur_dir);
+ pstrcat(cur_dir,"\\");
dos_clean_name(cur_dir);
if (!strequal(cur_dir,"\\"))
if (!chkpath(dname,True))
- strcpy(cur_dir,saved_dir);
+ pstrcpy(cur_dir,saved_dir);
- strcpy(cd_path,cur_dir);
+ pstrcpy(cd_path,cur_dir);
}
/****************************************************************************
@@ -465,7 +455,7 @@ static void cmd_cd(char *inbuf,char *outbuf)
{
fstring buf;
- if (next_token(NULL,buf,NULL))
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
do_cd(buf);
else
DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir)));
@@ -477,216 +467,206 @@ static void cmd_cd(char *inbuf,char *outbuf)
****************************************************************************/
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),
+ if (do_this_one(finfo)) {
+ time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
+ DEBUG(0,(" %-30s%7.7s%.0f %s",
+ CNV_LANG(finfo->name),
attrib_string(finfo->mode),
- finfo->size,
- asctime(LocalTime(&t,GMT_TO_LOCAL))));
+ (double)finfo->size,
+ asctime(LocalTime(&t))));
+ dir_total += finfo->size;
+ }
}
+
/****************************************************************************
- do a directory listing, calling fn on each file found
+ calculate size of a file
****************************************************************************/
-void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
+static void do_du(file_info *finfo)
{
- 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;
+ if (do_this_one(finfo)) {
+ dir_total += finfo->size;
+ }
}
-/*******************************************************************
- decide if a file should be operated on
- ********************************************************************/
-static BOOL do_this_one(file_info *finfo)
-{
- if (finfo->mode & aDIR) return(True);
-
- if (newer_than && finfo->mtime < newer_than)
- return(False);
-
- if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
- 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)
+ do a directory listing, calling fn on each file found. Use the TRANSACT2
+ call for long filenames
+ ****************************************************************************/
+static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
{
- finfo->mode = CVAL(p,21);
+ 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;
- /* 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);
-}
+ 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;
-/****************************************************************************
-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)
-{
- if (finfo)
- memcpy(finfo,&def_finfo,sizeof(*finfo));
+ uint16 setup;
+ pstring param;
- switch (level)
+ pstrcpy(mask,Mask);
+
+ while (ff_eos == 0)
{
- case 1: /* OS/2 understands this */
- if (finfo)
+ loop_count++;
+ if (loop_count > 200)
{
- /* 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);
+ DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
+ break;
}
- return(28 + CVAL(p,26));
- case 2: /* this is what OS/2 uses mostly */
- if (finfo)
+ if (First)
{
- /* 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);
+ 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);
+ pstrcpy(param+12,mask);
}
- return(32 + CVAL(p,30));
-
- /* levels 3 and 4 are untested */
- case 3:
- if (finfo)
+ else
{
- /* 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);
+ 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 */
+ pstrcpy(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));
}
- return(SVAL(p,4)+4);
+ /* ??? original code added 1 pad byte after param */
- case 4:
- if (finfo)
+ cli_send_trans_request(outbuf,SMBtrans2,NULL,0,FID_UNUSED,0,
+ NULL,param,&setup,
+ 0,12+strlen(mask)+1,1,
+ BUFFER_SIZE,10,0);
+
+ if (!cli_receive_trans_response(inbuf,SMBtrans2,
+ &resp_data_len,&resp_param_len,
+ &resp_data,&resp_param))
{
- /* 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(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
+ break;
}
- return(SVAL(p,4)+4);
- case 260: /* NT uses this, but also accepts 2 */
- if (finfo)
+ /* parse out some important return info */
+ p = resp_param;
+ if (First)
{
- int ret = SVAL(p,0);
- int namelen;
- p += 4; /* next entry offset */
- p += 4; /* fileindex */
+ 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);
+ }
- /* 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??
+ if (ff_searchcount == 0)
+ break;
- 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 */
+ /* point to the data bytes */
+ p = resp_data;
- 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);
+ /* 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);
+ /* pstrcpy(mask,p+ff_lastname+94); */
+ break;
+ case 1:
+ pstrcpy(mask,p + ff_lastname + 1);
+ ff_resume_key = 0;
+ break;
+ }
}
- return(SVAL(p,0));
- }
-
- DEBUG(1,("Unknown long filename format %d\n",level));
- return(SVAL(p,0));
-}
+ else
+ pstrcpy(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;
+ }
+ /* 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;
-/****************************************************************************
- 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)
-{
+ total_received += ff_searchcount;
- 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))
- {
- pstring mask2;
- pstring sav_dir;
- strcpy(sav_dir,cur_dir);
- strcat(cur_dir,finfo->name);
- strcat(cur_dir,"\\");
- strcpy(mask2,cur_dir);
+ if (resp_data) free(resp_data); resp_data = NULL;
+ if (resp_param) free(resp_param); resp_param = NULL;
- if (!fn)
- DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
+ DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
+ ff_searchcount,ff_eos,ff_resume_key));
- strcat(mask2,"*");
+ First = False;
+ }
- if (longdir)
- do_long_dir(inbuf,outbuf,mask2,attribute,fn,True);
- else
- do_dir(inbuf,outbuf,mask2,attribute,fn,True);
+ if (!fn)
+ for (p=dirlist,i=0;i<total_received;i++)
+ {
+ p += interpret_long_filename(info_level,p,&finfo);
+ display_finfo(&finfo);
+ }
- strcpy(cur_dir,sav_dir);
- }
- else
- {
- if (fn && do_this_one(finfo))
- fn(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, dirstoo);
}
+
+ /* free up the dirlist buffer */
+ if (dirlist) free(dirlist);
+ return(total_received);
}
/****************************************************************************
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 int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
{
char *p;
int received = 0;
@@ -703,7 +683,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
bzero(status,21);
- strcpy(mask,Mask);
+ pstrcpy(mask,Mask);
while (1)
{
@@ -721,7 +701,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
CVAL(outbuf,smb_com) = SMBsearch;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,num_asked);
SSVAL(outbuf,smb_vwv1,attribute);
@@ -730,9 +710,9 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
*p++ = 4;
if (first)
- strcpy(p,mask);
+ pstrcpy(p,mask);
else
- strcpy(p,"");
+ pstrcpy(p,"");
p += strlen(p) + 1;
*p++ = 5;
@@ -746,7 +726,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
}
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
received = SVAL(inbuf,smb_vwv0);
@@ -782,12 +762,12 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
CVAL(outbuf,smb_com) = SMBfclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,"");
+ pstrcpy(p,"");
p += strlen(p) + 1;
*p++ = 5;
@@ -796,7 +776,7 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
memcpy(p,status,21);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT,False);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf)));
@@ -813,290 +793,315 @@ static int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (
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);
+ dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False,dirstoo);
}
if (dirlist) free(dirlist);
return(num_received);
}
+
+
/****************************************************************************
- receive a SMB trans or trans2 response allocating the necessary memory
+ do a directory listing, calling fn on each file found
****************************************************************************/
-static BOOL receive_trans_response(char *inbuf,int trans,
- int *data_len,int *param_len,
- char **data,char **param)
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo)
{
- int total_data=0;
- int total_param=0;
- int this_data,this_param;
+ 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,dirstoo) > 0)
+ return;
+ }
- *data_len = *param_len = 0;
+ expand_mask(Mask,False);
+ do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir,dirstoo);
+ return;
+}
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
- show_msg(inbuf);
+/*******************************************************************
+ decide if a file should be operated on
+ ********************************************************************/
+static BOOL do_this_one(file_info *finfo)
+{
+ if (finfo->mode & aDIR) return(True);
- /* 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)
+ if (newer_than && finfo->mtime < newer_than)
return(False);
- /* parse out the lengths */
- total_data = SVAL(inbuf,smb_tdrcnt);
- total_param = SVAL(inbuf,smb_tprcnt);
+ if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH))
+ return(False);
- /* allocate it */
- *data = Realloc(*data,total_data);
- *param = Realloc(*param,total_param);
+ return(True);
+}
- 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);
+/*****************************************************************************
+ 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;
- /* 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);
+ if( offset >= rdrcnt )
+ {
+ DEBUG(1,("bad char ptr: datap=%u, converter=%u, rdata=%lu, rdrcnt=%d>", datap, converter, (unsigned long)rdata, rdrcnt));
+ return "<ERROR>";
}
-
- return(True);
+ else
+ {
+ return &rdata[offset];
+ }
+ }
}
/****************************************************************************
- do a directory listing, calling fn on each file found. Use the TRANSACT2
- call for long filenames
- ****************************************************************************/
-static int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir)
+interpret a short filename structure
+The length of the structure is returned
+****************************************************************************/
+static int interpret_short_filename(char *p,file_info *finfo)
{
- 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;
+ finfo->mode = CVAL(p,21);
- uint16 setup;
- pstring param;
+ /* 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);
+ pstrcpy(finfo->name,p+30);
+
+ return(DIR_STRUCT_SIZE);
+}
- strcpy(mask,Mask);
+/****************************************************************************
+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)
+{
+ if (finfo)
+ memcpy(finfo,&def_finfo,sizeof(*finfo));
- while (ff_eos == 0)
+ switch (level)
{
- loop_count++;
- if (loop_count > 200)
+ case 1: /* OS/2 understands this */
+ if (finfo)
{
- DEBUG(0,("ERROR: Looping in FIND_NEXT??\n"));
- break;
+ /* 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);
+ pstrcpy(finfo->name,p+27);
}
+ return(28 + CVAL(p,26));
- if (First)
- {
- 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);
- }
- else
+ case 2: /* this is what OS/2 uses mostly */
+ if (finfo)
{
- 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));
+ /* 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);
+ pstrcpy(finfo->name,p+31);
}
- /* ??? 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);
+ return(32 + CVAL(p,30));
- if (!receive_trans_response(inbuf,SMBtrans2,
- &resp_data_len,&resp_param_len,
- &resp_data,&resp_param))
+ /* levels 3 and 4 are untested */
+ case 3:
+ if (finfo)
{
- DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf)));
- break;
+ /* 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);
+ pstrcpy(finfo->name,p+33);
}
+ return(SVAL(p,4)+4);
- /* parse out some important return info */
- p = resp_param;
- if (First)
+ case 4:
+ if (finfo)
{
- ff_dir_handle = SVAL(p,0);
- ff_searchcount = SVAL(p,2);
- ff_eos = SVAL(p,4);
- ff_lastname = SVAL(p,8);
+ /* 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);
+ pstrcpy(finfo->name,p+37);
}
- else
+ return(SVAL(p,4)+4);
+
+ case 260: /* NT uses this, but also accepts 2 */
+ if (finfo)
{
- ff_searchcount = SVAL(p,0);
- ff_eos = SVAL(p,2);
- ff_lastname = SVAL(p,6);
- }
+ int ret = SVAL(p,0);
+ int namelen;
+ p += 4; /* next entry offset */
+ p += 4; /* fileindex */
- if (ff_searchcount == 0)
- break;
+ /* 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??
- /* point to the data bytes */
- p = resp_data;
+ 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 */
- /* 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;
- }
+ 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);
}
- else
- strcpy(mask,"");
-
- /* and add them to the dirlist pool */
- dirlist = Realloc(dirlist,dirlist_len + resp_data_len);
+ return(SVAL(p,0));
+ }
- if (!dirlist)
+ DEBUG(1,("Unknown long filename format %d\n",level));
+ return(SVAL(p,0));
+}
+
+
+
+
+/****************************************************************************
+ act on the files in a dir listing
+
+ RJS, 4-Apr-1998, dirstoo added to allow caller to indicate that directories
+ should be processed as well.
+ ****************************************************************************/
+static void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(file_info *),BOOL longdir, BOOL dirstoo)
+{
+
+ 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))
{
- DEBUG(0,("Failed to expand dirlist\n"));
- break;
- }
+ pstring mask2;
+ pstring sav_dir;
- /* 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));
- }
+ if (fn && dirstoo && do_this_one(finfo)) { /* Do dirs, RJS */
+ fn(finfo);
+ }
- /* grab the data for later use */
- memcpy(dirlist+dirlist_len,p,resp_data_len);
- dirlist_len += resp_data_len;
+ pstrcpy(sav_dir,cur_dir);
+ pstrcat(cur_dir,finfo->name);
+ pstrcat(cur_dir,"\\");
+ pstrcpy(mask2,cur_dir);
- total_received += ff_searchcount;
+ if (!fn)
+ DEBUG(0,("\n%s\n",CNV_LANG(cur_dir)));
- if (resp_data) free(resp_data); resp_data = NULL;
- if (resp_param) free(resp_param); resp_param = NULL;
+ pstrcat(mask2,"*");
- DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
- ff_searchcount,ff_eos,ff_resume_key));
+ if (longdir)
+ do_long_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);
+ else
+ do_dir(inbuf,outbuf,mask2,attribute,fn,True, dirstoo);
- First = False;
+ pstrcpy(cur_dir,sav_dir);
+ }
+ else
+ {
+ if (fn && do_this_one(finfo))
+ fn(finfo);
+ }
}
+}
- 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++)
+/****************************************************************************
+ get a directory listing
+ ****************************************************************************/
+static void cmd_dir(char *inbuf,char *outbuf)
+{
+ int attribute = aDIR | aSYSTEM | aHIDDEN;
+ pstring mask;
+ fstring buf;
+ char *p=buf;
+
+ dir_total = 0;
+ pstrcpy(mask,cur_dir);
+ if(mask[strlen(mask)-1]!='\\')
+ pstrcat(mask,"\\");
+
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
{
- p += interpret_long_filename(info_level,p,&finfo);
- dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True);
+ if (*p == '\\')
+ pstrcpy(mask,p);
+ else
+ pstrcat(mask,p);
}
+ else {
+ pstrcat(mask,"*");
+ }
- /* free up the dirlist buffer */
- if (dirlist) free(dirlist);
- return(total_received);
+ do_dir(inbuf,outbuf,mask,attribute,NULL,recurse,False);
+
+ do_dskattr();
+
+ DEBUG(3, ("Total bytes listed: %d\n", dir_total));
}
/****************************************************************************
get a directory listing
****************************************************************************/
-static void cmd_dir(char *inbuf,char *outbuf)
+static void cmd_du(char *inbuf,char *outbuf)
{
int attribute = aDIR | aSYSTEM | aHIDDEN;
pstring mask;
fstring buf;
char *p=buf;
- strcpy(mask,cur_dir);
+ dir_total = 0;
+ pstrcpy(mask,cur_dir);
if(mask[strlen(mask)-1]!='\\')
- strcat(mask,"\\");
+ pstrcat(mask,"\\");
- if (next_token(NULL,buf,NULL))
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
{
if (*p == '\\')
- strcpy(mask,p);
+ pstrcpy(mask,p);
else
- strcat(mask,p);
+ pstrcat(mask,p);
}
else {
- strcat(mask,"*");
+ pstrcat(mask,"*");
}
- do_dir(inbuf,outbuf,mask,attribute,NULL,recurse);
+ do_dir(inbuf,outbuf,mask,attribute,do_du,recurse,False);
do_dskattr();
-}
-
+ DEBUG(0, ("Total number of bytes: %d\n", dir_total));
+}
/****************************************************************************
get a file from rname to lname
@@ -1140,17 +1145,19 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
CVAL(outbuf,smb_com) = SMBopenX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv2,1);
+ SSVAL(outbuf,smb_vwv2,1); /* return additional info */
SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
SSVAL(outbuf,smb_vwv8,1);
+ SSVAL(outbuf,smb_vwv11,0xffff);
+ SSVAL(outbuf,smb_vwv12,0xffff);
p = smb_buf(outbuf);
- strcpy(p,rname);
+ pstrcpy(p,rname);
p = skip_string(p,1);
/* do a chained openX with a readX? */
@@ -1162,7 +1169,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
SSVAL(outbuf,smb_vwv1,smb_offset(p,outbuf));
bzero(p,200);
p -= smb_wct;
- SSVAL(p,smb_wct,10);
+ SCVAL(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));
@@ -1185,13 +1192,13 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
}
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_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))
+ cli_reopen_connection(inbuf,outbuf))
{
do_get(rname,lname,finfo1);
return;
@@ -1203,7 +1210,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
return;
}
- strcpy(finfo.name,rname);
+ pstrcpy(finfo.name,rname);
if (!finfo1)
{
@@ -1233,9 +1240,9 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
}
- DEBUG(2,("getting file %s of size %d bytes as %s ",
+ DEBUG(2,("getting file %s of size %.0f bytes as %s ",
CNV_LANG(finfo.name),
- finfo.size,
+ (double)finfo.size,
lname));
while (nread < finfo.size && !close_done)
@@ -1245,7 +1252,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
p=NULL;
- DEBUG(3,("nread=%d max_xmit=%d fsize=%d\n",nread,max_xmit,finfo.size));
+ DEBUG(3,("nread=%d max_xmit=%d fsize=%.0f\n",nread,max_xmit,(double)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 */
@@ -1281,7 +1288,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,10,0,True);
CVAL(outbuf,smb_com) = SMBreadX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
if (close_done)
{
@@ -1312,7 +1319,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
}
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -1345,7 +1352,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,8,0,True);
CVAL(outbuf,smb_com) = SMBreadbraw;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SIVAL(outbuf,smb_vwv1,nread);
SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
@@ -1397,7 +1404,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,5,0,True);
CVAL(outbuf,smb_com) = SMBread;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
@@ -1405,7 +1412,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
SSVAL(outbuf,smb_vwv4,finfo.size - nread);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -1439,17 +1446,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
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);
+ cli_smb_close(inbuf, outbuf, Client, cnum, fnum);
if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
{
@@ -1469,17 +1466,17 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,8,strlen(rname)+4,True);
CVAL(outbuf,smb_com) = SMBsetatr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,finfo.mode & ~(aARCH));
SIVALS(outbuf,smb_vwv1,0);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,rname);
+ pstrcpy(p,rname);
p += strlen(p)+1;
*p++ = 4;
*p = 0;
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
}
{
@@ -1493,7 +1490,7 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
get_total_time_ms += this_time;
get_total_size += finfo.size;
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+ DEBUG(1,("(%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)));
}
@@ -1505,25 +1502,25 @@ static void do_get(char *rname,char *lname,file_info *finfo1)
/****************************************************************************
get a file
****************************************************************************/
-static void cmd_get(void)
+static void cmd_get(char *dum_in, char *dum_out)
{
pstring lname;
pstring rname;
char *p;
- strcpy(rname,cur_dir);
- strcat(rname,"\\");
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,"\\");
p = rname + strlen(rname);
- if (!next_token(NULL,p,NULL)) {
+ if (!next_token(NULL,p,NULL,sizeof(rname)-strlen(rname))) {
DEBUG(0,("get <filename>\n"));
return;
}
- strcpy(lname,p);
+ pstrcpy(lname,p);
dos_clean_name(rname);
- next_token(NULL,lname,NULL);
+ next_token(NULL,lname,NULL,sizeof(lname));
do_get(rname,lname,NULL);
}
@@ -1547,9 +1544,11 @@ static void do_mget(file_info *finfo)
}
if (finfo->mode & aDIR)
- sprintf(quest,"Get directory %s? ",CNV_LANG(finfo->name));
+ slprintf(quest,sizeof(pstring)-1,
+ "Get directory %s? ",CNV_LANG(finfo->name));
else
- sprintf(quest,"Get file %s? ",CNV_LANG(finfo->name));
+ slprintf(quest,sizeof(pstring)-1,
+ "Get file %s? ",CNV_LANG(finfo->name));
if (prompt && !yesno(quest)) return;
@@ -1568,10 +1567,10 @@ static void do_mget(file_info *finfo)
return;
}
- strcpy(saved_curdir,cur_dir);
+ 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);
{
@@ -1579,36 +1578,36 @@ static void do_mget(file_info *finfo)
strlower(finfo->name);
if (!directory_exist(finfo->name,NULL) &&
- sys_mkdir(finfo->name,0777) != 0)
+ dos_mkdir(finfo->name,0777) != 0)
{
DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name)));
- strcpy(cur_dir,saved_curdir);
+ pstrcpy(cur_dir,saved_curdir);
free(inbuf);free(outbuf);
return;
}
- if (sys_chdir(finfo->name) != 0)
+ if (dos_chdir(finfo->name) != 0)
{
DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name)));
- strcpy(cur_dir,saved_curdir);
+ pstrcpy(cur_dir,saved_curdir);
free(inbuf);free(outbuf);
return;
}
}
- strcpy(mget_mask,cur_dir);
- strcat(mget_mask,"*");
+ pstrcpy(mget_mask,cur_dir);
+ pstrcat(mget_mask,"*");
do_dir((char *)inbuf,(char *)outbuf,
- mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False);
+ mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False, False);
chdir("..");
- strcpy(cur_dir,saved_curdir);
+ pstrcpy(cur_dir,saved_curdir);
free(inbuf);free(outbuf);
}
else
{
- strcpy(rname,cur_dir);
- strcat(rname,finfo->name);
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,finfo->name);
do_get(rname,finfo->name,finfo);
}
}
@@ -1616,17 +1615,19 @@ static void do_mget(file_info *finfo)
/****************************************************************************
view the file using the pager
****************************************************************************/
-static void cmd_more(void)
+static void cmd_more(char *dum_in, char *dum_out)
{
fstring rname,lname,tmpname,pager_cmd;
char *pager;
- strcpy(rname,cur_dir);
- strcat(rname,"\\");
- sprintf(tmpname,"/tmp/smbmore.%d",getpid());
- strcpy(lname,tmpname);
+ fstrcpy(rname,cur_dir);
+ fstrcat(rname,"\\");
+ slprintf(tmpname,
+ sizeof(fstring)-1,
+ "%s/smbmore.%d",tmpdir(),(int)getpid());
+ fstrcpy(lname,tmpname);
- if (!next_token(NULL,rname+strlen(rname),NULL)) {
+ if (!next_token(NULL,rname+strlen(rname),NULL,sizeof(rname)-strlen(rname))) {
DEBUG(0,("more <filename>\n"));
return;
}
@@ -1635,7 +1636,9 @@ static void cmd_more(void)
do_get(rname,lname,NULL);
pager=getenv("PAGER");
- sprintf(pager_cmd,"%s %s",(pager? pager:PAGER), tmpname);
+
+ slprintf(pager_cmd,sizeof(pager_cmd)-1,
+ "%s %s",(pager? pager:PAGER), tmpname);
system(pager_cmd);
unlink(tmpname);
}
@@ -1659,26 +1662,26 @@ static void cmd_mget(char *inbuf,char *outbuf)
abort_mget = False;
- while (next_token(NULL,p,NULL))
+ while (next_token(NULL,p,NULL,sizeof(buf)))
{
- strcpy(mget_mask,cur_dir);
+ pstrcpy(mget_mask,cur_dir);
if(mget_mask[strlen(mget_mask)-1]!='\\')
- strcat(mget_mask,"\\");
+ pstrcat(mget_mask,"\\");
if (*p == '\\')
- strcpy(mget_mask,p);
+ pstrcpy(mget_mask,p);
else
- strcat(mget_mask,p);
- do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False);
+ pstrcat(mget_mask,p);
+ do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
}
if (! *mget_mask)
{
- strcpy(mget_mask,cur_dir);
+ pstrcpy(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);
+ pstrcat(mget_mask,"\\");
+ pstrcat(mget_mask,"*");
+ do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False,False);
}
}
@@ -1704,15 +1707,15 @@ static BOOL do_mkdir(char *name)
CVAL(outbuf,smb_com) = SMBmkdir;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,name);
+ pstrcpy(p,name);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -1737,15 +1740,15 @@ static void cmd_mkdir(char *inbuf,char *outbuf)
fstring buf;
char *p=buf;
- strcpy(mask,cur_dir);
+ pstrcpy(mask,cur_dir);
- if (!next_token(NULL,p,NULL))
+ if (!next_token(NULL,p,NULL,sizeof(buf)))
{
if (!recurse)
DEBUG(0,("mkdir <dirname>\n"));
return;
}
- strcat(mask,p);
+ pstrcat(mask,p);
if (recurse)
{
@@ -1753,17 +1756,17 @@ static void cmd_mkdir(char *inbuf,char *outbuf)
pstring ddir2;
*ddir2 = 0;
- strcpy(ddir,mask);
+ pstrcpy(ddir,mask);
trim_string(ddir,".",NULL);
p = strtok(ddir,"/\\");
while (p)
{
- strcat(ddir2,p);
+ pstrcat(ddir2,p);
if (!chkpath(ddir2,False))
{
do_mkdir(ddir2);
}
- strcat(ddir2,"\\");
+ pstrcat(ddir2,"\\");
p = strtok(NULL,"/\\");
}
}
@@ -1786,7 +1789,7 @@ static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
CVAL(outbuf,smb_com) = SMBwritebraw;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n);
@@ -1795,7 +1798,7 @@ static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
send_smb(Client,outbuf);
- if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
+ if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
return(0);
_smb_setlen(buf-4,n); /* HACK! XXXX */
@@ -1803,7 +1806,7 @@ static int smb_writeraw(char *outbuf,int fnum,int pos,char *buf,int n)
if (write_socket(Client,buf-4,n+4) != n+4)
return(0);
- if (!receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
+ if (!client_receive_smb(Client,inbuf,CLIENT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0) {
DEBUG(0,("Error writing remote file (2)\n"));
return(0);
}
@@ -1828,7 +1831,7 @@ static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
CVAL(outbuf,smb_com) = SMBwrite;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n);
@@ -1840,7 +1843,7 @@ static int smb_writefile(char *outbuf,int fnum,int pos,char *buf,int n)
memcpy(smb_buf(outbuf)+3,buf,n);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0) {
DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
@@ -1885,17 +1888,17 @@ static void do_put(char *rname,char *lname,file_info *finfo)
CVAL(outbuf,smb_com) = SMBcreate;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_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);
+ pstrcpy(p,rname);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -1905,7 +1908,15 @@ static void do_put(char *rname,char *lname,file_info *finfo)
return;
}
- f = fopen(lname,"r");
+ /* allow files to be piped into smbclient
+ jdblair 24.jun.98 */
+ if (!strcmp(lname, "-")) {
+ f = stdin;
+ /* size of file is not known */
+ finfo->size = 0;
+ } else {
+ f = fopen(lname,"r");
+ }
if (!f)
{
@@ -1919,20 +1930,26 @@ static void do_put(char *rname,char *lname,file_info *finfo)
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 of size %.0f bytes as %s ",lname,(double)finfo->size,CNV_LANG(rname)));
if (!maxwrite)
maxwrite = writebraw_supported?MAX(max_xmit,BUFFER_SIZE):(max_xmit-200);
- while (nread < finfo->size)
+ /* This is a rewrite of the read/write loop that doesn't require the input
+ file to be of a known length. This allows the stream pointer 'f' to
+ refer to stdin.
+
+ Rather than reallocing the read buffer every loop to keep it the min
+ necessary length this look uses a fixed length buffer and just tests
+ for eof on the file stream at the top of each loop.
+ jdblair, 24.jun.98 */
+
+ buf = (char *)malloc(maxwrite+4);
+ while (! feof(f) )
{
int n = maxwrite;
int ret;
- n = MIN(n,finfo->size - nread);
-
- buf = (char *)Realloc(buf,n+4);
-
fseek(f,nread,SEEK_SET);
if ((n = readfile(buf+4,1,n,f)) < 1)
{
@@ -1955,19 +1972,17 @@ static void do_put(char *rname,char *lname,file_info *finfo)
nread += n;
}
-
-
bzero(outbuf,smb_size);
set_message(outbuf,3,0,True);
CVAL(outbuf,smb_com) = SMBclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
put_dos_date3(outbuf,smb_vwv1,close_time);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -1994,18 +2009,18 @@ static void do_put(char *rname,char *lname,file_info *finfo)
put_total_time_ms += this_time;
put_total_size += finfo->size;
- DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
+ DEBUG(1,("(%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)));
}
-}
+}
/****************************************************************************
put a file
****************************************************************************/
-static void cmd_put(void)
+static void cmd_put(char *dum_in, char *dum_out)
{
pstring lname;
pstring rname;
@@ -2014,27 +2029,30 @@ static void cmd_put(void)
file_info finfo;
finfo = def_finfo;
- strcpy(rname,cur_dir);
- strcat(rname,"\\");
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,"\\");
- if (!next_token(NULL,p,NULL))
+ if (!next_token(NULL,p,NULL,sizeof(buf)))
{
DEBUG(0,("put <filename>\n"));
return;
}
- strcpy(lname,p);
+ pstrcpy(lname,p);
- if (next_token(NULL,p,NULL))
- strcat(rname,p);
+ if (next_token(NULL,p,NULL,sizeof(buf)))
+ pstrcat(rname,p);
else
- strcat(rname,lname);
+ pstrcat(rname,lname);
dos_clean_name(rname);
{
- struct stat st;
- if (!file_exist(lname,&st)) {
+ SMB_STRUCT_STAT st;
+ /* allow '-' to represent stdin
+ jdblair, 24.jun.98 */
+ if (!file_exist(lname,&st) &&
+ (strcmp(lname,"-"))) {
DEBUG(0,("%s does not exist\n",lname));
return;
}
@@ -2057,7 +2075,7 @@ static BOOL seek_list(FILE *f,char *name)
trim_string(s,"./",NULL);
if (strncmp(s,name,strlen(name)) != 0)
{
- strcpy(name,s);
+ pstrcpy(name,s);
return(True);
}
}
@@ -2069,17 +2087,17 @@ static BOOL seek_list(FILE *f,char *name)
/****************************************************************************
set the file selection mask
****************************************************************************/
-static void cmd_select(void)
+static void cmd_select(char *dum_in, char *dum_out)
{
- strcpy(fileselection,"");
- next_token(NULL,fileselection,NULL);
+ pstrcpy(fileselection,"");
+ next_token(NULL,fileselection,NULL,sizeof(fileselection));
}
/****************************************************************************
mput some files
****************************************************************************/
-static void cmd_mput(void)
+static void cmd_mput(char *dum_in, char *dum_out)
{
pstring lname;
pstring rname;
@@ -2090,18 +2108,21 @@ static void cmd_mput(void)
finfo = def_finfo;
- while (next_token(NULL,p,NULL))
+ while (next_token(NULL,p,NULL,sizeof(buf)))
{
- struct stat st;
+ SMB_STRUCT_STAT st;
pstring cmd;
pstring tmpname;
FILE *f;
- sprintf(tmpname,"/tmp/ls.smb.%d",(int)getpid());
+ slprintf(tmpname,sizeof(pstring)-1,
+ "%s/ls.smb.%d",tmpdir(),(int)getpid());
if (recurse)
- sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpname);
+ slprintf(cmd,sizeof(pstring)-1,
+ "find . -name \"%s\" -print > %s",p,tmpname);
else
- sprintf(cmd,"/bin/ls %s > %s",p,tmpname);
+ slprintf(cmd,sizeof(pstring)-1,
+ "/bin/ls %s > %s",p,tmpname);
system(cmd);
f = fopen(tmpname,"r");
@@ -2120,34 +2141,35 @@ static void cmd_mput(void)
if (directory_exist(lname,&st))
{
if (!recurse) continue;
- sprintf(quest,"Put directory %s? ",lname);
+ slprintf(quest,sizeof(pstring)-1,
+ "Put directory %s? ",lname);
if (prompt && !yesno(quest))
{
- strcat(lname,"/");
+ pstrcat(lname,"/");
if (!seek_list(f,lname))
break;
goto again1;
}
- strcpy(rname,cur_dir);
- strcat(rname,lname);
- if (!do_mkdir(rname))
- {
- strcat(lname,"/");
- if (!seek_list(f,lname))
- break;
- goto again1;
- }
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,lname);
+ if (!chkpath(rname,False) && !do_mkdir(rname)) {
+ pstrcat(lname,"/");
+ if (!seek_list(f,lname))
+ break;
+ goto again1;
+ }
continue;
}
else
{
- sprintf(quest,"Put file %s? ",lname);
+ slprintf(quest,sizeof(quest)-1,
+ "Put file %s? ",lname);
if (prompt && !yesno(quest)) continue;
- strcpy(rname,cur_dir);
- strcat(rname,lname);
+ pstrcpy(rname,cur_dir);
+ pstrcat(rname,lname);
}
dos_format(rname);
@@ -2178,19 +2200,19 @@ static void do_cancel(int job)
bzero(param,sizeof(param));
p = param;
- SSVAL(p,0,81); /* api number */
+ SSVAL(p,0,81); /* DosPrintJobDel() */
p += 2;
- strcpy(p,"W");
+ pstrcpy(p,"W");
p = skip_string(p,1);
- strcpy(p,"");
+ pstrcpy(p,"");
p = skip_string(p,1);
SSVAL(p,0,job);
p += 2;
- if (call_api(PTR_DIFF(p,param),0,
- 6,1000,
+ if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
+ 6, 1000,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -2225,54 +2247,17 @@ static void cmd_cancel(char *inbuf,char *outbuf )
DEBUG(0,("Trying to cancel print jobs without -P may fail\n"));
}
- if (!next_token(NULL,buf,NULL)) {
+ if (!next_token(NULL,buf,NULL,sizeof(buf))) {
printf("cancel <jobid> ...\n");
return;
}
do {
job = atoi(buf);
do_cancel(job);
- } while (next_token(NULL,buf,NULL));
+ } while (next_token(NULL,buf,NULL,sizeof(buf)));
}
-/****************************************************************************
- get info on a file
- ****************************************************************************/
-static void cmd_stat(char *inbuf,char *outbuf)
-{
- 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;
-}
/****************************************************************************
@@ -2293,19 +2278,19 @@ static void cmd_print(char *inbuf,char *outbuf )
DEBUG(0,("Trying to print without -P may fail\n"));
}
- if (!next_token(NULL,lname,NULL))
+ if (!next_token(NULL,lname,NULL, sizeof(lname)))
{
DEBUG(0,("print <filename>\n"));
return;
}
- strcpy(rname,lname);
+ pstrcpy(rname,lname);
p = strrchr(rname,'/');
if (p)
{
pstring tname;
- strcpy(tname,p+1);
- strcpy(rname,tname);
+ pstrcpy(tname,p+1);
+ pstrcpy(rname,tname);
}
if ((int)strlen(rname) > 14)
@@ -2314,7 +2299,7 @@ static void cmd_print(char *inbuf,char *outbuf )
if (strequal(lname,"-"))
{
f = stdin;
- strcpy(rname,"stdin");
+ pstrcpy(rname,"stdin");
}
dos_clean_name(rname);
@@ -2324,17 +2309,17 @@ static void cmd_print(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBsplopen;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0);
SSVAL(outbuf,smb_vwv1,printmode);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,rname);
+ pstrcpy(p,rname);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -2380,7 +2365,7 @@ static void cmd_print(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBsplwr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n+3);
@@ -2388,7 +2373,7 @@ static void cmd_print(char *inbuf,char *outbuf )
SSVAL(smb_buf(outbuf),1,n);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -2405,12 +2390,12 @@ static void cmd_print(char *inbuf,char *outbuf )
set_message(outbuf,1,0,True);
CVAL(outbuf,smb_com) = SMBsplclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -2425,7 +2410,8 @@ static void cmd_print(char *inbuf,char *outbuf )
}
/****************************************************************************
-print a file
+ show a print queue - this is deprecated as it uses the old smb that
+ has limited support - the correct call is the cmd_p_queue_4() after this.
****************************************************************************/
static void cmd_queue(char *inbuf,char *outbuf )
{
@@ -2437,13 +2423,13 @@ static void cmd_queue(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBsplretq;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_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);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -2468,13 +2454,13 @@ static void cmd_queue(char *inbuf,char *outbuf )
{
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;
+ case 0x01: safe_strcpy(status,"held or stopped", sizeof(status)-1); break;
+ case 0x02: safe_strcpy(status,"printing",sizeof(status)-1); break;
+ case 0x03: safe_strcpy(status,"awaiting print", sizeof(status)-1); break;
+ case 0x04: safe_strcpy(status,"in intercept",sizeof(status)-1); break;
+ case 0x05: safe_strcpy(status,"file had error",sizeof(status)-1); break;
+ case 0x06: safe_strcpy(status,"printer error",sizeof(status)-1); break;
+ default: safe_strcpy(status,"unknown",sizeof(status)-1); break;
}
DEBUG(0,("%-6d %-16.16s %-9d %s\n",
@@ -2487,6 +2473,222 @@ static void cmd_queue(char *inbuf,char *outbuf )
/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_p_queue_4(char *inbuf,char *outbuf )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code=0;
+
+ 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"));
+ }
+
+ bzero(param,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,strrchr(service,'\\')+1); /* 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(1,("Calling DosPrintJobEnum()...\n"));
+ if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
+ 10, 4096,
+ &rprcnt, &rdrcnt,
+ param, NULL, NULL,
+ &rparam, &rdata) )
+ {
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+ if (result_code == 0) /* if no error, */
+ {
+ int i;
+ uint16 JobId;
+ uint16 Priority;
+ uint32 Size;
+ char *UserName;
+ char *JobName;
+ char *JobTimeStr;
+ time_t JobTime;
+ fstring PrinterName;
+
+ fstrcpy(PrinterName,strrchr(service,'\\')+1); /* name of queue */
+ strlower(PrinterName); /* in lower case */
+
+ p = rdata; /* received data */
+ for( i = 0; i < SVAL(rparam,4); ++i)
+ {
+ JobId = SVAL(p,0);
+ Priority = SVAL(p,2);
+ UserName = fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt);
+ strlower(UserName);
+ Priority = SVAL(p,2);
+ JobTime = make_unix_date3( p + 12);
+ JobTimeStr = asctime(LocalTime( &JobTime));
+ Size = IVAL(p,16);
+ JobName = fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt);
+
+
+ printf("%s-%u %s priority %u %s %s %u bytes\n",
+ PrinterName, JobId, UserName,
+ Priority, JobTimeStr, JobName, Size);
+
+#if 0 /* DEBUG code */
+ printf("Job Id: \"%u\"\n", SVAL(p,0));
+ printf("Priority: \"%u\"\n", SVAL(p,2));
+
+ printf("User Name: \"%s\"\n", fix_char_ptr(SVAL(p,4), converter, rdata, rdrcnt) );
+ printf("Position: \"%u\"\n", SVAL(p,8));
+ printf("Status: \"%u\"\n", SVAL(p,10));
+
+ JobTime = make_unix_date3( p + 12);
+ printf("Submitted: \"%s\"\n", asctime(LocalTime(&JobTime)));
+ printf("date: \"%u\"\n", SVAL(p,12));
+
+ printf("Size: \"%u\"\n", SVAL(p,16));
+ printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+ printf("Document: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+#endif /* DEBUG CODE */
+ p += 28;
+ }
+ }
+ }
+ else /* cli_call_api() failed */
+ {
+ printf("Failed, error = %d\n", result_code);
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ if(rparam) free(rparam);
+ if(rdata) free(rdata);
+
+ return;
+}
+
+/****************************************************************************
+show information about a print queue
+****************************************************************************/
+static void cmd_qinfo(char *inbuf,char *outbuf )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code=0;
+
+ bzero(param,sizeof(param));
+
+ p = param;
+ SSVAL(p,0,70); /* API function number 70 (DosPrintQGetInfo) */
+ p += 2;
+ pstrcpy(p,"zWrLh"); /* parameter description? */
+ p = skip_string(p,1);
+ pstrcpy(p,"zWWWWzzzzWWzzl"); /* returned data format */
+ p = skip_string(p,1);
+ pstrcpy(p,strrchr(service,'\\')+1); /* name of queue */
+ p = skip_string(p,1);
+ SSVAL(p,0,3); /* API function level 3, just queue info, no job info */
+ SSVAL(p,2,1000); /* size of bytes of returned data buffer */
+ p += 4;
+ pstrcpy(p,""); /* subformat */
+ p = skip_string(p,1);
+
+ DEBUG(1,("Calling DosPrintQueueGetInfo()...\n"));
+ if( cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param), 0, 0,
+ 10, 4096,
+ &rprcnt, &rdrcnt,
+ param, NULL, NULL,
+ &rparam, &rdata) )
+ {
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ DEBUG(2,("returned %d bytes of parameters, %d bytes of data, %d records\n", rprcnt, rdrcnt, SVAL(rparam,4) ));
+
+ if (result_code == 0) /* if no error, */
+ {
+ p = rdata; /* received data */
+
+ printf("Name: \"%s\"\n", fix_char_ptr(SVAL(p,0), converter, rdata, rdrcnt) );
+ printf("Priority: %u\n", SVAL(p,4) );
+ printf("Start time: %u\n", SVAL(p,6) );
+ printf("Until time: %u\n", SVAL(p,8) );
+ printf("Seperator file: \"%s\"\n", fix_char_ptr(SVAL(p,12), converter, rdata, rdrcnt) );
+ printf("Print processor: \"%s\"\n", fix_char_ptr(SVAL(p,16), converter, rdata, rdrcnt) );
+ printf("Parameters: \"%s\"\n", fix_char_ptr(SVAL(p,20), converter, rdata, rdrcnt) );
+ printf("Comment: \"%s\"\n", fix_char_ptr(SVAL(p,24), converter, rdata, rdrcnt) );
+ printf("Status: %u\n", SVAL(p,28) );
+ printf("Jobs: %u\n", SVAL(p,30) );
+ printf("Printers: \"%s\"\n", fix_char_ptr(SVAL(p,32), converter, rdata, rdrcnt) );
+ printf("Drivername: \"%s\"\n", fix_char_ptr(SVAL(p,36), converter, rdata, rdrcnt) );
+
+ /* Dump the driver data */
+ {
+ int count, x, y, c;
+ char *ddptr;
+
+ ddptr = rdata + SVAL(p,40) - converter;
+ if( SVAL(p,40) == 0 ) {count = 0;} else {count = IVAL(ddptr,0);}
+ printf("Driverdata: size=%d, version=%u\n", count, IVAL(ddptr,4) );
+
+ for(x=8; x < count; x+=16)
+ {
+ for(y=0; y < 16; y++)
+ {
+ if( (x+y) < count )
+ printf("%2.2X ", CVAL(ddptr,(x+y)) );
+ else
+ fputs(" ", stdout);
+ }
+ for(y=0; y < 16 && (x+y) < count; y++)
+ {
+ c = CVAL(ddptr,(x+y));
+ if(isprint(c))
+ fputc(c, stdout);
+ else
+ fputc('.', stdout);
+ }
+ fputc('\n', stdout);
+ }
+ }
+
+ }
+ }
+ else /* cli_call_api() failed */
+ {
+ printf("Failed, error = %d\n", result_code);
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ if(rparam) free(rparam);
+ if(rdata) free(rdata);
+
+ return;
+}
+
+/****************************************************************************
delete some files
****************************************************************************/
static void do_del(file_info *finfo)
@@ -2495,8 +2697,8 @@ static void do_del(file_info *finfo)
char *inbuf,*outbuf;
pstring mask;
- strcpy(mask,cur_dir);
- strcat(mask,finfo->name);
+ pstrcpy(mask,cur_dir);
+ pstrcat(mask,finfo->name);
if (finfo->mode & aDIR)
return;
@@ -2515,16 +2717,16 @@ static void do_del(file_info *finfo)
CVAL(outbuf,smb_com) = SMBunlink;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,mask);
+ pstrcpy(p,mask);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_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)));
@@ -2545,16 +2747,16 @@ static void cmd_del(char *inbuf,char *outbuf )
if (recurse)
attribute |= aDIR;
- strcpy(mask,cur_dir);
+ pstrcpy(mask,cur_dir);
- if (!next_token(NULL,buf,NULL))
+ if (!next_token(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0,("del <filename>\n"));
return;
}
- strcat(mask,buf);
+ pstrcat(mask,buf);
- do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False);
+ do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False,False);
}
@@ -2567,29 +2769,29 @@ static void cmd_rmdir(char *inbuf,char *outbuf )
fstring buf;
char *p;
- strcpy(mask,cur_dir);
+ pstrcpy(mask,cur_dir);
- if (!next_token(NULL,buf,NULL))
+ if (!next_token(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0,("rmdir <dirname>\n"));
return;
}
- strcat(mask,buf);
+ pstrcat(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);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,mask);
+ pstrcpy(p,mask);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -2608,16 +2810,17 @@ static void cmd_rename(char *inbuf,char *outbuf )
fstring buf,buf2;
char *p;
- strcpy(src,cur_dir);
- strcpy(dest,cur_dir);
+ pstrcpy(src,cur_dir);
+ pstrcpy(dest,cur_dir);
- if (!next_token(NULL,buf,NULL) || !next_token(NULL,buf2,NULL))
+ if (!next_token(NULL,buf,NULL,sizeof(buf)) ||
+ !next_token(NULL,buf2,NULL, sizeof(buf2)))
{
DEBUG(0,("rename <src> <dest>\n"));
return;
}
- strcat(src,buf);
- strcat(dest,buf2);
+ pstrcat(src,buf);
+ pstrcat(dest,buf2);
bzero(outbuf,smb_size);
set_message(outbuf,1,4 + strlen(src) + strlen(dest),True);
@@ -2625,17 +2828,17 @@ static void cmd_rename(char *inbuf,char *outbuf )
CVAL(outbuf,smb_com) = SMBmv;
SSVAL(outbuf,smb_tid,cnum);
SSVAL(outbuf,smb_vwv0,aHIDDEN | aDIR | aSYSTEM);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,src);
+ pstrcpy(p,src);
p = skip_string(p,1);
*p++ = 4;
- strcpy(p,dest);
+ pstrcpy(p,dest);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -2649,7 +2852,7 @@ static void cmd_rename(char *inbuf,char *outbuf )
/****************************************************************************
toggle the prompt flag
****************************************************************************/
-static void cmd_prompt(void)
+static void cmd_prompt(char *dum_in, char *dum_out)
{
prompt = !prompt;
DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
@@ -2659,18 +2862,18 @@ static void cmd_prompt(void)
/****************************************************************************
set the newer than time
****************************************************************************/
-static void cmd_newer(void)
+static void cmd_newer(char *dum_in, char *dum_out)
{
fstring buf;
BOOL ok;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
- ok = next_token(NULL,buf,NULL);
- if (ok && (sys_stat(buf,&sbuf) == 0))
+ ok = next_token(NULL,buf,NULL,sizeof(buf));
+ if (ok && (dos_stat(buf,&sbuf) == 0))
{
newer_than = sbuf.st_mtime;
DEBUG(1,("Getting files newer than %s",
- asctime(LocalTime(&newer_than,GMT_TO_LOCAL))));
+ asctime(LocalTime(&newer_than))));
}
else
newer_than = 0;
@@ -2682,11 +2885,11 @@ static void cmd_newer(void)
/****************************************************************************
set the archive level
****************************************************************************/
-static void cmd_archive(void)
+static void cmd_archive(char *dum_in, char *dum_out)
{
fstring buf;
- if (next_token(NULL,buf,NULL)) {
+ if (next_token(NULL,buf,NULL,sizeof(buf))) {
archive_level = atoi(buf);
} else
DEBUG(0,("Archive level is %d\n",archive_level));
@@ -2695,7 +2898,7 @@ static void cmd_archive(void)
/****************************************************************************
toggle the lowercaseflag
****************************************************************************/
-static void cmd_lowercase(void)
+static void cmd_lowercase(char *dum_in, char *dum_out)
{
lowercase = !lowercase;
DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
@@ -2707,7 +2910,7 @@ static void cmd_lowercase(void)
/****************************************************************************
toggle the recurse flag
****************************************************************************/
-static void cmd_recurse(void)
+static void cmd_recurse(char *dum_in, char *dum_out)
{
recurse = !recurse;
DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
@@ -2716,7 +2919,7 @@ static void cmd_recurse(void)
/****************************************************************************
toggle the translate flag
****************************************************************************/
-static void cmd_translate(void)
+static void cmd_translate(char *dum_in, char *dum_out)
{
translation = !translation;
DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
@@ -2727,12 +2930,12 @@ static void cmd_translate(void)
/****************************************************************************
do a printmode command
****************************************************************************/
-static void cmd_printmode(void)
+static void cmd_printmode(char *dum_in, char *dum_out)
{
fstring buf;
fstring mode;
- if (next_token(NULL,buf,NULL))
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
{
if (strequal(buf,"text"))
printmode = 0;
@@ -2748,13 +2951,13 @@ static void cmd_printmode(void)
switch(printmode)
{
case 0:
- strcpy(mode,"text");
+ fstrcpy(mode,"text");
break;
case 1:
- strcpy(mode,"graphics");
+ fstrcpy(mode,"graphics");
break;
default:
- sprintf(mode,"%d",printmode);
+ slprintf(mode,sizeof(mode)-1,"%d",printmode);
break;
}
@@ -2764,663 +2967,22 @@ static void cmd_printmode(void)
/****************************************************************************
do the lcd command
****************************************************************************/
-static void cmd_lcd(void)
+static void cmd_lcd(char *dum_in, char *dum_out)
{
fstring buf;
pstring d;
- if (next_token(NULL,buf,NULL))
- sys_chdir(buf);
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
+ dos_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);
-}
-
-
-/****************************************************************************
-send a login 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);
- }
- 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));
-
- if (was_null)
- {
- free(inbuf);
- free(outbuf);
- }
- return True;
-}
-
-
-/****************************************************************************
-send a logout command
-****************************************************************************/
-static void send_logout(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)));
- }
-
-
-#ifdef STATS
- stats_report();
-#endif
- exit(0);
-}
-
-
-
-/****************************************************************************
-call a remote api
-****************************************************************************/
-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 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);
-
- send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
- data,param,NULL,
- drcnt,prcnt,0,
- mdrcnt,mprcnt,0);
-
- return (receive_trans_response(inbuf,SMBtrans,
- rdrcnt,rprcnt,
- rdata,rparam));
-}
-
-/****************************************************************************
- 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;
@@ -3432,74 +2994,77 @@ static BOOL browse_host(BOOL sort)
p = param;
SSVAL(p,0,0); /* api number */
p += 2;
- strcpy(p,"WrLeh");
+ pstrcpy(p,"WrLeh");
p = skip_string(p,1);
- strcpy(p,"B13BWz");
+ pstrcpy(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 (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
+ 1024, BUFFER_SIZE,
+ &rprcnt,&rdrcnt,
+ param,NULL, 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);
+ if (res == 0 || res == ERRmoredata)
+ {
+ count=SVAL(rparam,4);
+ p = rdata;
- 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;
+ if (count > 0)
+ {
+ printf("\n\tSharename Type Comment\n");
+ printf("\t--------- ---- -------\n");
+ }
- 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;
- }
+ if (sort)
+ qsort(p,count,20,QSORT_CAST StrCaseCmp);
- printf("\t%-15.15s%-10.10s%s\n",
- sname,
- typestr,
- comment_offset?rdata+comment_offset-converter:"");
+ 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:
+ 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;
+ }
+
+ printf("\t%-15.15s%-10.10s%s\n",
+ sname, typestr,
+ comment_offset?rdata+comment_offset-converter:"");
- if (strlen(sname)>8) long_share_name=True;
+ if (strlen(sname)>8) long_share_name=True;
- p += 20;
- }
+ 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 (long_share_name) {
+ printf("\nNOTE: There were share names longer than 8 chars.\n\
+On older clients these may not be accessible or may give browsing errors\n");
+ }
+
+ if(res == ERRmoredata)
+ printf("\nNOTE: More data was available, the list was truncated.\n");
}
+ }
if (rparam) free(rparam);
if (rdata) free(rdata);
@@ -3511,7 +3076,7 @@ static BOOL browse_host(BOOL sort)
/****************************************************************************
get some server info
****************************************************************************/
-static void server_info()
+static void server_info(void)
{
char *rparam = NULL;
char *rdata = NULL;
@@ -3522,20 +3087,20 @@ static void server_info()
bzero(param,sizeof(param));
p = param;
- SSVAL(p,0,63); /* api number */
+ SSVAL(p,0,63); /* NetServerGetInfo()? */
p += 2;
- strcpy(p,"WrLh");
+ pstrcpy(p,"WrLh");
p = skip_string(p,1);
- strcpy(p,"zzzBBzz");
+ pstrcpy(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,
+ if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p,param),0, 0,
+ 6, 1000,
&rprcnt,&rdrcnt,
- param,NULL,
+ param,NULL, NULL,
&rparam,&rdata))
{
int res = SVAL(rparam,0);
@@ -3563,164 +3128,191 @@ static void server_info()
/****************************************************************************
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;
+ char *p,*svtype_p;
pstring param;
int uLevel = 1;
int count = 0;
+ BOOL ok = False;
+ BOOL generic_request = False;
+
+
+ if (strequal(wk_grp,"WORKGROUP")) {
+ /* we won't specify a workgroup */
+ generic_request = True;
+ }
/* now send a SMBtrans command with api ServerEnum? */
p = param;
SSVAL(p,0,0x68); /* api number */
p += 2;
- strcpy(p,"WrLehDO");
+
+ pstrcpy(p,generic_request?"WrLehDO":"WrLehDz");
p = skip_string(p,1);
- strcpy(p,"B16BBDz");
-#if 0
- strcpy(p,getenv("XX_STR2"));
-#endif
+ pstrcpy(p,"B16BBDz");
p = skip_string(p,1);
SSVAL(p,0,uLevel);
- SSVAL(p,2,0x2000); /* buf length */
+ SSVAL(p,2,BUFFER_SIZE - SAFETY_MARGIN); /* buf length */
p += 4;
- SIVAL(p,0,SV_TYPE_ALL);
+ svtype_p = p;
+ p += 4;
- 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 (!generic_request) {
+ pstrcpy(p, wk_grp);
+ p = skip_string(p,1);
+ }
- if (res == 0) {
- char *p2 = rdata;
- count=SVAL(rparam,4);
+ /* first ask for a list of servers in this workgroup */
+ SIVAL(svtype_p,0,SV_TYPE_ALL);
- if (count > 0) {
- printf("\n\nThis machine has a browse list:\n");
- printf("\n\tServer Comment\n");
- printf("\t--------- -------\n");
- }
+ if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
+ 8, BUFFER_SIZE - SAFETY_MARGIN,
+ &rprcnt,&rdrcnt,
+ param,NULL, NULL,
+ &rparam,&rdata))
+ {
+ int res = SVAL(rparam,0);
+ int converter=SVAL(rparam,2);
+ int i;
+
+ if (res == 0 || res == ERRmoredata) {
+ 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");
+ }
- 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;
- }
+ 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:"");
+
+ ok=True;
+ p2 += 26;
}
+
+ if(res == ERRmoredata)
+ printf("\nNOTE: More data was available, the list was truncated.\n");
}
+ }
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);
+ /* now ask for a list of workgroups */
+ SIVAL(svtype_p,0,SV_TYPE_DOMAIN_ENUM);
- if (count > 0) {
- printf("\n\nThis machine has a workgroup list:\n");
- printf("\n\tWorkgroup Master\n");
- printf("\t--------- -------\n");
- }
+ if (cli_call_api(PIPE_LANMAN, 0,PTR_DIFF(p+4,param),0, 0,
+ 8, BUFFER_SIZE - SAFETY_MARGIN,
+ &rprcnt,&rdrcnt,
+ param,NULL, NULL,
+ &rparam,&rdata))
+ {
+ int res = SVAL(rparam,0);
+ int converter=SVAL(rparam,2);
+ int i;
+
+ if (res == 0 || res == ERRmoredata) {
+ 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:"");
+ 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;
- }
+ ok=True;
+ p2 += 26;
}
+
+ if(res == ERRmoredata)
+ printf("\nNOTE: More data was available, the list was truncated.\n");
}
+ }
if (rparam) free(rparam);
if (rdata) free(rdata);
- return(count>0);
+ return(ok);
}
+/* 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 */
struct
{
char *name;
- void (*fn)();
+ void (*fn)(char *, char *);
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)" },
+ {"ls",cmd_dir,"<mask> list the contents of the current directory",{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}},
+ {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
+ {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
+ {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
+ {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
+ {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
+ {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
+ {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
+ {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
+ {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
+ {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+ {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
+ {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+ {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
+ {"pq",cmd_p_queue_4,"enumerate the print queue",{COMPL_NONE,COMPL_NONE}},
+ {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
+ {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
+ {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
+ {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,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}},
+ {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
+ {"qinfo",cmd_qinfo,"show print queue information",{COMPL_NONE,COMPL_NONE}},
+ {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
+ {"quit",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"q",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"exit",cli_send_logout,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+ {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
+ {"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}},
+ {"tar",cmd_tar,"tar <c|x>[IXbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
+ {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
{"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}
+ "<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
+ {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
+ {"help",cmd_help,"[command] give help on a command",{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}}
};
@@ -3742,7 +3334,7 @@ static int process_tok(fstring tok)
cmd = i;
break;
}
- else if (strnequal(commands[i].name, tok, tok_len+1))
+ else if (strnequal(commands[i].name, tok, tok_len))
{
matches++;
cmd = i;
@@ -3761,12 +3353,12 @@ static int process_tok(fstring tok)
/****************************************************************************
help
****************************************************************************/
-void cmd_help(void)
+static void cmd_help(char *dum_in, char *dum_out)
{
int i=0,j;
fstring buf;
- if (next_token(NULL,buf,NULL))
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
{
if ((i = process_tok(buf)) >= 0)
DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));
@@ -3782,203 +3374,225 @@ void cmd_help(void)
}
}
-/****************************************************************************
-open the client sockets
-****************************************************************************/
-static BOOL open_sockets(int port )
-{
- static int last_port;
- char *host;
- pstring service2;
- extern int Client;
-#ifdef USENMB
- BOOL failed = True;
-#endif
-
- 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;
-
- if ((bcast = open_socket_in(SOCK_DGRAM, 0, 3)) != -1) {
- set_socket_options (bcast, "SO_BROADCAST");
-
- if (!got_bcast && get_myname(hs, &ip1)) {
- get_broadcast(&ip1, &bcast_ip, &ip2);
- }
-
- if (name_query(bcast, host, 0x20, True, True, bcast_ip, &dest_ip,0)){
- failed = False;
- }
- close (bcast);
- }
-#endif
- if (failed) {
- DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
- return False;
- }
- }
- }
-
- 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;
-}
+#ifndef HAVE_LIBREADLINE
/****************************************************************************
wait for keyboard activity, swallowing network packets
****************************************************************************/
-#ifdef CLIX
-static char wait_keyboard(char *buffer)
-#else
static void wait_keyboard(char *buffer)
-#endif
{
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
timeout.tv_sec = 20;
timeout.tv_usec = 0;
-#ifdef CLIX
- timeout.tv_sec = 0;
-#endif
- selrtn = sys_select(&fds,&timeout);
+ sys_select(MAX(Client,fileno(stdin))+1,&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
+
+ /* 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(Client,&fds))
receive_smb(Client,buffer,0);
-#ifdef CLIX
- delay++;
- if (delay > 100000)
- {
- delay = 0;
- chkpath("\\",False);
- }
-#else
chkpath("\\",False);
-#endif
}
}
+#else /* if HAVE_LIBREADLINE */
/****************************************************************************
-close and open the connection again
+ completion routines for GNU Readline
****************************************************************************/
-BOOL reopen_connection(char *inbuf,char *outbuf)
+
+/* To avoid filename completion being activated when no valid
+ completions are found, we assign this stub completion function
+ to the rl_completion_entry_function variable. */
+
+char *complete_cmd_null(char *text, int state)
{
- static int open_count=0;
+ return NULL;
+}
- open_count++;
+/* Argh. This is starting to get ugly. We need to be able to pass data
+ back from the do_dir() iterator function. */
- if (open_count>5) return(False);
+static int compl_state;
+static char *compl_text;
+static pstring result;
- DEBUG(1,("Trying to re-open connection\n"));
+/* Iterator function for do_dir() */
- set_message(outbuf,0,0,True);
- SCVAL(outbuf,smb_com,SMBtdis);
- SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+void complete_process_file(file_info *f)
+{
+ /* Do we have a partial match? */
- send_smb(Client,outbuf);
- receive_smb(Client,inbuf,SHORT_TIMEOUT);
+ if ((compl_state >= 0) && (strncmp(compl_text, f->name,
+ strlen(compl_text)) == 0)) {
+
+ /* Return filename if we have made enough matches */
+
+ if (compl_state == 0) {
+ pstrcpy(result, f->name);
+ compl_state = -1;
+
+ return;
+ }
+ compl_state--;
+ }
+}
+
+/* Complete a remote file */
+
+char *complete_remote_file(char *text, int state)
+{
+ char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ int attribute = aDIR | aSYSTEM | aHIDDEN;
+ pstring mask;
+
+ if ((InBuffer == NULL) || (OutBuffer == NULL))
+ return(NULL);
+
+ /* Create dir mask */
+
+ pstrcpy(mask, cur_dir);
+ pstrcat(mask, "*");
+
+ /* Initialise static vars for filename match */
+
+ compl_text = text;
+ compl_state = state;
+ result[0] = '\0';
+
+ /* Iterate over all files in directory */
+
+ do_dir(InBuffer, OutBuffer, mask, attribute, complete_process_file, False,
+ True);
+
+ /* Clean up */
+
+ free(InBuffer);
+ free(OutBuffer);
+
+ /* Return matched filename */
- close_sockets();
- if (!open_sockets(0)) return(False);
+ if (result[0] != '\0') {
+ return strdup(result); /* Readline will dispose of strings */
+ } else {
+ return NULL;
+ }
+}
+
+/* Complete a smbclient command */
+
+char *complete_cmd(char *text, int state)
+{
+ static int cmd_index;
+ char *name;
+
+ /* Initialise */
+
+ if (state == 0) {
+ cmd_index = 0;
+ }
- return(send_login(inbuf,outbuf,True,True));
+ /* Return the next name which partially matches the list of commands */
+
+ while (strlen(name = commands[cmd_index++].name) > 0) {
+ if (strncmp(name, text, strlen(text)) == 0) {
+ return strdup(name);
+ }
+ }
+
+ return NULL;
}
+/* Main completion function for smbclient. Work out which word we are
+ trying to complete and call the appropriate function. */
+
+char **completion_fn(char *text, int start, int end)
+{
+ int i, num_words, cmd_index;
+ char lastch = ' ';
+
+ /* If we are at the start of a word, we are completing a smbclient
+ command. */
+
+ if (start == 0) {
+ return completion_matches(text, complete_cmd);
+ }
+
+ /* Count # of words in command */
+
+ num_words = 0;
+ for (i = 0; i <= end; i++) {
+ if ((rl_line_buffer[i] != ' ') && (lastch == ' '))
+ num_words++;
+ lastch = rl_line_buffer[i];
+ }
+
+ if (rl_line_buffer[end] == ' ')
+ num_words++;
+
+ /* Work out which command we are completing for */
+
+ for (cmd_index = 0; strcmp(commands[cmd_index].name, "") != 0;
+ cmd_index++) {
+
+ /* Check each command in array */
+
+ if (strncmp(rl_line_buffer, commands[cmd_index].name,
+ strlen(commands[cmd_index].name)) == 0) {
+
+ /* Call appropriate completion function */
+
+ if ((num_words == 2) || (num_words == 3)) {
+ switch (commands[cmd_index].compl_args[num_words - 2]) {
+
+ case COMPL_REMOTE:
+ return completion_matches(text, complete_remote_file);
+ break;
+
+ case COMPL_LOCAL:
+ return completion_matches(text, filename_completion_function);
+ break;
+
+ default:
+ /* An invalid completion type */
+ break;
+ }
+ }
+
+ /* We're either completing an argument > 3 or found an invalid
+ completion type. Either way do nothing about it. */
+
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+#endif /* HAVE_LIBREADLINE */
+
/****************************************************************************
process commands from the client
****************************************************************************/
-BOOL process(char *base_directory)
+static BOOL process(char *base_directory)
{
- extern FILE *dbf;
pstring line;
+ char *cmd;
char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -3988,37 +3602,89 @@ BOOL process(char *base_directory)
bzero(OutBuffer,smb_size);
- if (!send_login(InBuffer,OutBuffer,True,True))
+ if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
return(False);
if (*base_directory) do_cd(base_directory);
- while (!feof(stdin))
+ cmd = cmdstr;
+ if (cmd[0] != '\0') while (cmd[0] != '\0')
+ {
+ char *p;
+ fstring tok;
+ int i;
+
+ if ((p = strchr(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;
+ }
+
+ /* input language code to internal one */
+ CNV_INPUT (line);
+
+ /* and get the first part of the command */
+ {
+ char *ptr = line;
+ if (!next_token(&ptr,tok,NULL,sizeof(tok))) 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)));
+ }
+ else while (!feof(stdin))
{
fstring tok;
int i;
bzero(OutBuffer,smb_size);
- /* display a prompt */
- DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir)));
- fflush(dbf);
+#ifdef HAVE_LIBREADLINE
+
+ {
+ pstring prompt;
+
+ /* Read input using GNU Readline */
+
+ slprintf(prompt, sizeof(prompt) - 1, "smb: %s> ", CNV_LANG(cur_dir));
+ if (!readline(prompt))
+ break;
+
+ /* Copy read line to samba buffer */
+
+ pstrcpy(line, rl_line_buffer);
+ pstrcat(line, "\n");
+
+ /* Add line to history */
+
+ if (strlen(line) > 0)
+ add_history(line);
+ }
-#ifdef CLIX
- line[0] = wait_keyboard(InBuffer);
- /* this might not be such a good idea... */
- if ( line[0] == EOF)
- break;
#else
+
+ /* display a prompt */
+ DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
+ dbgflush( );
+
wait_keyboard(InBuffer);
-#endif
/* and get a response */
-#ifdef CLIX
- fgets( &line[1],999, stdin);
-#else
if (!fgets(line,1000,stdin))
break;
+
#endif
/* input language code to internal one */
@@ -4034,7 +3700,7 @@ BOOL process(char *base_directory)
/* and get the first part of the command */
{
char *ptr = line;
- if (!next_token(&ptr,tok,NULL)) continue;
+ if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
}
if ((i = process_tok(tok)) >= 0)
@@ -4045,25 +3711,20 @@ BOOL process(char *base_directory)
DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
}
- send_logout();
+ cli_send_logout(InBuffer,OutBuffer);
return(True);
}
-
/****************************************************************************
usage on the program
****************************************************************************/
-void usage(char *pname)
+static void usage(char *pname)
{
DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
pname));
-#ifdef KANJI
- DEBUG(0,("[-t termcode] "));
-#endif /* KANJI */
-
DEBUG(0,("\nVersion %s\n",VERSION));
- DEBUG(0,("\t-p port listen on the specified port\n"));
+ DEBUG(0,("\t-p port connect to 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"));
@@ -4073,38 +3734,50 @@ void usage(char *pname)
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-R name resolve order use these name resolution services only\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-c command string execute semicolon separated commands\n"));
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-T<c|x>IXgbNan command line tar\n"));
DEBUG(0,("\t-D directory start from directory\n"));
DEBUG(0,("\n"));
}
-
-
/****************************************************************************
main program
****************************************************************************/
-int main(int argc,char *argv[])
+ int main(int argc,char *argv[])
{
fstring base_directory;
char *pname = argv[0];
- int port = 139;
+ int port = SMB_PORT;
int opt;
extern FILE *dbf;
extern char *optarg;
extern int optind;
pstring query_host;
BOOL message = False;
+ BOOL nt_domain_logon = False;
+ BOOL explicit_user = False;
extern char tar_type;
+ static pstring servicesf = CONFIGFILE;
+ pstring term_code;
+ pstring new_name_resolve_order;
+ char *p;
+
+#ifdef KANJI
+ pstrcpy(term_code, KANJI);
+#else /* KANJI */
+ *term_code = 0;
+#endif /* KANJI */
*query_host = 0;
*base_directory = 0;
+ *new_name_resolve_order = 0;
+
DEBUGLEVEL = 2;
setup_logging(pname,True);
@@ -4112,6 +3785,28 @@ int main(int argc,char *argv[])
TimeInit();
charset_initialise();
+ if(!get_myname(myhostname,NULL))
+ {
+ DEBUG(0,("Failed to get my hostname.\n"));
+ }
+
+ in_client = True;
+
+ if (!lp_load(servicesf,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ }
+
+ codepage_initialise(lp_client_code_page());
+
+ interpret_coding_system(term_code);
+
+#ifdef WITH_SSL
+ sslutil_init(0);
+#endif
+
+ pstrcpy(workgroup,lp_workgroup());
+
+ load_interfaces();
pid = getpid();
uid = getuid();
gid = getgid();
@@ -4120,14 +3815,85 @@ int main(int argc,char *argv[])
umask(myumask);
if (getenv("USER"))
+ {
+ pstrcpy(username,getenv("USER"));
+
+ /* modification to support userid%passwd syntax in the USER var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if ((p=strchr(username,'%')))
{
- strcpy(username,getenv("USER"));
- strupper(username);
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
+ }
+ strupper(username);
+ }
+
+ /* modification to support PASSWD environmental var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if (getenv("PASSWD")) {
+ pstrcpy(password,getenv("PASSWD"));
+ got_pass = True;
+ }
+
+ if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
+ int fd = -1;
+ 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 = open(p, O_RDONLY);
+ 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);
+ got_pass = True;
+ if (close_it)
+ close(fd);
+ }
if (*username == 0 && getenv("LOGNAME"))
{
- strcpy(username,getenv("LOGNAME"));
+ pstrcpy(username,getenv("LOGNAME"));
strupper(username);
}
@@ -4140,7 +3906,9 @@ int main(int argc,char *argv[])
if (*argv[1] != '-')
{
- strcpy(service,argv[1]);
+ pstrcpy(service,argv[1]);
+ /* Convert any '/' characters in the service name to '\' characters */
+ string_replace( service, '/','\\');
argc--;
argv++;
@@ -4163,39 +3931,42 @@ int main(int argc,char *argv[])
if (argc > 1 && (*argv[1] != '-'))
{
got_pass = True;
- strcpy(password,argv[1]);
+ pstrcpy(password,argv[1]);
memset(argv[1],'X',strlen(argv[1]));
argc--;
argv++;
}
}
-#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 */
+ while ((opt =
+ getopt(argc, argv,"s:B:O:R:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
switch (opt)
{
case 'm':
max_protocol = interpret_protocol(optarg,max_protocol);
break;
case 'O':
- strcpy(user_socket_options,optarg);
+ pstrcpy(user_socket_options,optarg);
break;
+ case 'R':
+ pstrcpy(new_name_resolve_order, optarg);
+ break;
+ case 'S':
+ pstrcpy(desthost,optarg);
+ strupper(desthost);
+ nt_domain_logon = True;
+ break;
case 'M':
- name_type = 3;
- strcpy(desthost,optarg);
+ name_type = 0x03; /* messages are sent to NetBIOS name type 0x3 */
+ pstrcpy(desthost,optarg);
strupper(desthost);
message = True;
break;
case 'B':
- bcast_ip = *interpret_addr2(optarg);
- got_bcast = True;
+ iface_set_default(NULL,optarg,NULL);
break;
case 'D':
- strcpy(base_directory,optarg);
+ pstrcpy(base_directory,optarg);
break;
case 'T':
if (!tar_parseargs(argc, argv, optarg, optind)) {
@@ -4204,20 +3975,23 @@ int main(int argc,char *argv[])
}
break;
case 'i':
- strcpy(scope,optarg);
+ pstrcpy(scope,optarg);
break;
case 'L':
got_pass = True;
- strcpy(query_host,optarg);
+ pstrcpy(query_host,optarg);
+ if(!explicit_user)
+ *username = '\0';
break;
case 'U':
{
- char *p;
- strcpy(username,optarg);
- if ((p=strchr(username,'%')))
+ char *lp;
+ explicit_user = True;
+ pstrcpy(username,optarg);
+ if ((lp=strchr(username,'%')))
{
- *p = 0;
- strcpy(password,p+1);
+ *lp = 0;
+ pstrcpy(password,lp+1);
got_pass = True;
memset(strchr(optarg,'%')+1,'X',strlen(password));
}
@@ -4225,7 +3999,7 @@ int main(int argc,char *argv[])
break;
case 'W':
- strcpy(workgroup,optarg);
+ pstrcpy(workgroup,optarg);
break;
case 'E':
dbf = stderr;
@@ -4238,10 +4012,11 @@ int main(int argc,char *argv[])
}
break;
case 'n':
- strcpy(myname,optarg);
+ pstrcpy(global_myname,optarg);
break;
case 'N':
got_pass = True;
+ no_pass = True;
break;
case 'P':
connect_as_printer = True;
@@ -4253,45 +4028,62 @@ int main(int argc,char *argv[])
DEBUGLEVEL = atoi(optarg);
break;
case 'l':
- sprintf(debugf,"%s.client",optarg);
+ slprintf(debugf,sizeof(debugf)-1, "%s.client",optarg);
break;
case 'p':
port = atoi(optarg);
break;
+ case 'c':
+ cmdstr = optarg;
+ got_pass = True;
+ break;
case 'h':
usage(pname);
exit(0);
break;
-#ifdef KANJI
+ case 's':
+ pstrcpy(servicesf, optarg);
+ break;
case 't':
- if (!setup_term_code (optarg)) {
- DEBUG(0, ("%s: unknown terminal code name\n", optarg));
- usage (pname);
- exit (1);
- }
+ pstrcpy(term_code, optarg);
break;
-#endif /* KANJI */
default:
usage(pname);
exit(1);
}
+ get_myname((*global_myname)?NULL:global_myname,NULL);
+ strupper(global_myname);
+
+ if(*new_name_resolve_order)
+ lp_set_name_resolve_order(new_name_resolve_order);
+
if (!tar_type && !*query_host && !*service && !message)
{
usage(pname);
exit(1);
}
+#ifdef HAVE_LIBREADLINE
+
+ /* Initialise GNU Readline */
+
+ rl_readline_name = "smbclient";
+ rl_attempted_completion_function = completion_fn;
+ rl_completion_entry_function = (Function *)complete_cmd_null;
+
+ /* Initialise history list */
+
+ using_history();
- DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
+#endif /* HAVE_LIBREADLINE */
- get_myname(*myname?NULL:myname,&myip);
- strupper(myname);
+ DEBUG( 3, ( "Client started (version %s).\n", VERSION ) );
if (tar_type) {
recurse=True;
- if (open_sockets(port)) {
+ if (cli_open_sockets(port)) {
char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
int ret;
@@ -4300,32 +4092,33 @@ int main(int argc,char *argv[])
return(1);
bzero(OutBuffer,smb_size);
- if (!send_login(InBuffer,OutBuffer,True,True))
+ if (!cli_send_login(InBuffer,OutBuffer,True,True,NULL))
return(False);
if (*base_directory) do_cd(base_directory);
ret=process_tar(InBuffer, OutBuffer);
- send_logout();
+ cli_send_logout(InBuffer, OutBuffer);
close_sockets();
return(ret);
} else
return(1);
}
- if (*query_host)
+ if (*query_host && !nt_domain_logon)
{
int ret = 0;
- sprintf(service,"\\\\%s\\IPC$",query_host);
+ slprintf(service,sizeof(service)-1,
+ "\\\\%s\\IPC$",query_host);
strupper(service);
connect_as_ipc = True;
- if (open_sockets(port))
+ if (cli_open_sockets(port))
{
#if 0
*username = 0;
#endif
- if (!send_login(NULL,NULL,True,True))
+ if (!cli_send_login(NULL,NULL,True,True,NULL))
return(1);
server_info();
@@ -4333,12 +4126,12 @@ int main(int argc,char *argv[])
sleep(1);
browse_host(True);
}
- if (!list_servers()) {
+ if (!list_servers(workgroup)) {
sleep(1);
- list_servers();
+ list_servers(workgroup);
}
- send_logout();
+ cli_send_logout(NULL,NULL);
close_sockets();
}
@@ -4348,11 +4141,11 @@ int main(int argc,char *argv[])
if (message)
{
int ret = 0;
- if (open_sockets(port))
+ if (cli_open_sockets(port))
{
pstring inbuf,outbuf;
bzero(outbuf,smb_size);
- if (!send_session_request(inbuf,outbuf))
+ if (!cli_send_session_request(inbuf,outbuf))
return(1);
send_message(inbuf,outbuf);
@@ -4363,7 +4156,7 @@ int main(int argc,char *argv[])
return(ret);
}
- if (open_sockets(port))
+ if (cli_open_sockets(port))
{
if (!process(base_directory))
{
@@ -4377,158 +4170,3 @@ int main(int argc,char *argv[])
return(0);
}
-
-
-/* error code stuff - put together by Merik Karman
- merik@blackadder.dsh.oz.au */
-
-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}};
-
-
-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 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;
- }
- }
-
- sprintf(ret,"%s - %d",err_classes[i].class,num);
- return ret;
- }
-
- sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
- return(ret);
-}
diff --git a/source/client/clientutil.c b/source/client/clientutil.c
new file mode 100644
index 00000000000..7f5943cb01f
--- /dev/null
+++ b/source/client/clientutil.c
@@ -0,0 +1,976 @@
+/*
+ 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+pstring service="";
+pstring desthost="";
+extern pstring global_myname;
+pstring password = "";
+pstring smb_login_passwd = "";
+pstring username="";
+pstring workgroup=WORKGROUP;
+BOOL got_pass = False;
+BOOL no_pass = False;
+BOOL connect_as_printer = False;
+BOOL connect_as_ipc = False;
+
+char cryptkey[8];
+BOOL doencrypt=False;
+
+extern pstring user_socket_options;
+
+/* 30 second timeout on most commands */
+#define CLIENT_TIMEOUT (30*1000)
+#define SHORT_TIMEOUT (5*1000)
+
+int name_type = 0x20;
+
+int max_protocol = PROTOCOL_NT1;
+
+BOOL readbraw_supported = False;
+BOOL writebraw_supported = False;
+
+extern int DEBUGLEVEL;
+
+int cnum = 0;
+int pid = 0;
+int gid = 0;
+int uid = 0;
+int mid = 0;
+
+int max_xmit = BUFFER_SIZE;
+
+BOOL have_ip = False;
+
+extern struct in_addr dest_ip;
+
+extern int Protocol;
+
+extern int Client;
+
+
+/****************************************************************************
+setup basics in a outgoing packet
+****************************************************************************/
+void cli_setup_pkt(char *outbuf)
+{
+ SSVAL(outbuf,smb_pid,pid);
+ SSVAL(outbuf,smb_uid,uid);
+ SSVAL(outbuf,smb_mid,mid);
+ if (Protocol > PROTOCOL_COREPLUS)
+ {
+ SCVAL(outbuf,smb_flg,0x8);
+ SSVAL(outbuf,smb_flg2,0x1);
+ }
+}
+
+/****************************************************************************
+call a remote api
+****************************************************************************/
+BOOL cli_call_api(char *pipe_name, int pipe_name_len,
+ int prcnt,int drcnt, int srcnt,
+ int mprcnt,int mdrcnt,
+ int *rprcnt,int *rdrcnt,
+ char *param,char *data, uint16 *setup,
+ char **rparam,char **rdata)
+{
+ 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);
+
+ if(!inbuf || !outbuf) {
+ DEBUG(0,("cli_call_api: malloc fail.\n"));
+ return False;
+ }
+
+ if (pipe_name_len == 0) pipe_name_len = strlen(pipe_name);
+
+ cli_send_trans_request(outbuf,SMBtrans,pipe_name, pipe_name_len, 0,0,
+ data, param, setup,
+ drcnt, prcnt, srcnt,
+ mdrcnt, mprcnt, 0);
+
+ return (cli_receive_trans_response(inbuf,SMBtrans,
+ rdrcnt,rprcnt,
+ rdata,rparam));
+}
+
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+BOOL cli_receive_trans_response(char *inbuf,int trans,
+ int *data_len,int *param_len,
+ char **data,char **param)
+{
+ int total_data=0;
+ int total_param=0;
+ int this_data,this_param;
+
+ *data_len = *param_len = 0;
+
+ client_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);
+
+ if((total_data && !data) || (total_param && !param)) {
+ DEBUG(0,("cli_receive_trans_response: Realloc fail !\n"));
+ return(False);
+ }
+
+ 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;
+
+ client_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);
+ }
+
+ return(True);
+}
+
+
+
+/****************************************************************************
+ send a SMB trans or trans2 request
+ ****************************************************************************/
+BOOL cli_send_trans_request(char *outbuf,int trans,
+ char *name,int namelen, 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);
+ cli_setup_pkt(outbuf);
+
+ outparam = smb_buf(outbuf)+(trans==SMBtrans ? namelen+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)
+ memcpy(p,name, namelen+1); /* 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 (!client_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);
+}
+
+
+/****************************************************************************
+send a session request
+****************************************************************************/
+BOOL cli_send_session_request(char *inbuf,char *outbuf)
+{
+ fstring dest;
+ char *p;
+ int len = 4;
+ /* send a session request (RFC 8002) */
+
+ fstrcpy(dest,desthost);
+ p = strchr(dest,'.');
+ if (p) *p = 0;
+
+ /* put in the destination name */
+ p = outbuf+len;
+ name_mangle(dest,p,name_type); /* 0x20 is the SMB server NetBIOS type. */
+ len += name_len(p);
+
+ /* and my name */
+ p = outbuf+len;
+ name_mangle(global_myname,p,0);
+ len += name_len(p);
+
+ /* setup the packet length */
+ _smb_setlen(outbuf,len);
+ CVAL(outbuf,0) = 0x81;
+
+#ifdef WITH_SSL
+retry:
+#endif /* WITH_SSL */
+
+ send_smb(Client,outbuf);
+ DEBUG(5,("Sent session request\n"));
+
+ client_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, LONG_CONNECT_TIMEOUT);
+ if (Client == -1)
+ return False;
+
+ DEBUG(3,("Retargeted\n"));
+
+ set_socket_options(Client,user_socket_options);
+
+ /* Try again */
+ return cli_send_session_request(inbuf,outbuf);
+ } /* C. Hoch 9/14/95 End */
+
+#ifdef WITH_SSL
+ if(CVAL(inbuf,0) == 0x83 && CVAL(inbuf,4) == 0x8e) { /* use ssl */
+ fprintf(stderr, "Making secure connection\n");
+ if(!sslutil_fd_is_ssl(Client)){
+ if(sslutil_connect(Client) == 0)
+ goto retry;
+ }
+ }
+#endif
+
+ 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,global_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",global_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);
+}
+
+static 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}
+};
+
+
+/****************************************************************************
+send a login command.
+****************************************************************************/
+BOOL cli_send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup, struct connection_options *options)
+{
+ BOOL was_null = (!inbuf && !outbuf);
+ time_t servertime = 0;
+ extern int serverzone;
+ int crypt_len=0;
+ char *pass = NULL;
+ uchar enc_ntpass[24];
+ int ntpasslen = 0;
+ pstring dev;
+ char *p;
+ int numprots;
+ int tries=0;
+ struct connection_options opt;
+
+ bzero(&opt, sizeof(opt));
+
+ if (was_null)
+ {
+ inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+ if(!inbuf || !outbuf) {
+ DEBUG(0,("cli_send_login: malloc fail !\n"));
+ return False;
+ }
+ }
+
+ if (strstr(service,"IPC$")) connect_as_ipc = True;
+
+ pstrcpy(dev,"A:");
+ if (connect_as_printer)
+ pstrcpy(dev,"LPT1:");
+ if (connect_as_ipc)
+ pstrcpy(dev,"IPC");
+
+
+ if (start_session && !cli_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;
+ pstrcpy(p,prots[numprots].name);
+ p += strlen(p) + 1;
+ }
+ }
+
+ CVAL(outbuf,smb_com) = SMBnegprot;
+ cli_setup_pkt(outbuf);
+
+ CVAL(smb_buf(outbuf),0) = 2;
+
+ send_smb(Client,outbuf);
+ client_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",
+ global_myname,desthost,smb_errstr(inbuf)));
+ if (was_null)
+ {
+ free(inbuf);
+ free(outbuf);
+ }
+ return(False);
+ }
+
+ opt.protocol = Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
+
+
+ if (Protocol < PROTOCOL_LANMAN1) {
+ /* no extra params */
+ } else if (Protocol < PROTOCOL_NT1) {
+ opt.sec_mode = SVAL(inbuf,smb_vwv1);
+ opt.max_xmit = max_xmit = SVAL(inbuf,smb_vwv2);
+ opt.sesskey = IVAL(inbuf,smb_vwv6);
+ opt.serverzone = 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) {
+ opt.rawmode = SVAL(inbuf,smb_vwv5);
+ 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)));
+ opt.max_vcs = SVAL(inbuf,smb_vwv4);
+ DEBUG(3,("max vcs %d\n",opt.max_vcs));
+ DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
+ } else {
+ /* NT protocol */
+ opt.sec_mode = CVAL(inbuf,smb_vwv1);
+ opt.max_xmit = max_xmit = IVAL(inbuf,smb_vwv3+1);
+ opt.sesskey = IVAL(inbuf,smb_vwv7+1);
+ opt.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)));
+ opt.max_vcs = SVAL(inbuf,smb_vwv2+1);
+ DEBUG(3,("max vcs %d\n",opt.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 = ((opt.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)),
+ -(double)(serverzone/3600.0)));
+ done_time = True;
+ }
+ }
+
+ get_pass:
+
+ if (got_pass)
+ pass = password;
+ else
+ pass = (char *)getpass("Password: ");
+
+ if(!pass)
+ pass = "";
+
+ pstrcpy(smb_login_passwd, pass);
+
+ /* use a blank username for the 2nd try with a blank password */
+ if (tries++ && !*pass)
+ *username = 0;
+
+ if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
+ {
+ fstring pword;
+ int passlen = strlen(pass)+1;
+ fstrcpy(pword,pass);
+
+ if (doencrypt && *pass)
+ {
+ DEBUG(3,("Using encrypted passwords\n"));
+ passlen = 24;
+ SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);
+ ntpasslen = 24;
+ SMBNTencrypt((uchar *)pass,(uchar *)cryptkey,enc_ntpass);
+ }
+
+ /* if in share level security then don't send a password now */
+ if (!(opt.sec_mode & 1)) {fstrcpy(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;
+ cli_setup_pkt(outbuf);
+
+ CVAL(outbuf,smb_vwv0) = 0xFF;
+ SSVAL(outbuf,smb_vwv2,max_xmit);
+ SSVAL(outbuf,smb_vwv3,2);
+ SSVAL(outbuf,smb_vwv4,opt.max_vcs-1);
+ SIVAL(outbuf,smb_vwv5,opt.sesskey);
+ SSVAL(outbuf,smb_vwv7,passlen);
+ p = smb_buf(outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ pstrcpy(p,username);
+ }
+ else
+ {
+ if (!doencrypt) passlen--;
+ /* for Win95 */
+ set_message(outbuf,13,0,True);
+ CVAL(outbuf,smb_com) = SMBsesssetupX;
+ cli_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,opt.sesskey);
+ SSVAL(outbuf,smb_vwv7,passlen);
+ SSVAL(outbuf,smb_vwv8,doencrypt ? ntpasslen : 0);
+ p = smb_buf(outbuf);
+ memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
+ if(doencrypt)
+ memcpy(p,enc_ntpass,ntpasslen); p += SVAL(outbuf,smb_vwv8);
+ pstrcpy(p,username);p = skip_string(p,1);
+ pstrcpy(p,workgroup);p = skip_string(p,1);
+ pstrcpy(p,"Unix");p = skip_string(p,1);
+ pstrcpy(p,"Samba");p = skip_string(p,1);
+ set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
+ }
+
+ send_smb(Client,outbuf);
+ client_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"));
+ if (! no_pass)
+ goto get_pass;
+ }
+
+ DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s %s\n",
+ username,global_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));
+ opt.server_uid = uid = SVAL(inbuf,smb_uid);
+ }
+
+ if (opt.sec_mode & 1) {
+ if (SVAL(inbuf, smb_vwv2) & 1)
+ DEBUG(1,("connected as guest "));
+ DEBUG(1,("security=user\n"));
+ } else {
+ DEBUG(1,("security=share\n"));
+ }
+
+ /* 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;
+ fstrcpy(pword,pass);
+
+ if (doencrypt && *pass) {
+ passlen=24;
+ SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);
+ }
+
+ /* if in user level security then don't send a password now */
+ if ((opt.sec_mode & 1)) {
+ fstrcpy(pword, ""); passlen=1;
+ }
+
+ if (Protocol <= PROTOCOL_COREPLUS) {
+ set_message(outbuf,0,6 + strlen(service) + passlen + strlen(dev),True);
+ CVAL(outbuf,smb_com) = SMBtcon;
+ cli_setup_pkt(outbuf);
+
+ p = smb_buf(outbuf);
+ *p++ = 0x04;
+ pstrcpy(p, service);
+ p = skip_string(p,1);
+ *p++ = 0x04;
+ memcpy(p,pword,passlen);
+ p += passlen;
+ *p++ = 0x04;
+ pstrcpy(p, dev);
+ }
+ else {
+ set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
+ CVAL(outbuf,smb_com) = SMBtconX;
+ cli_setup_pkt(outbuf);
+
+ SSVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv3,passlen);
+
+ p = smb_buf(outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ pstrcpy(p,service);
+ p = skip_string(p,1);
+ pstrcpy(p,dev);
+ }
+ }
+
+ send_smb(Client,outbuf);
+ client_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)));
+ pstrcpy(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);
+ }
+ return(False);
+ }
+
+
+ if (Protocol <= PROTOCOL_COREPLUS) {
+ max_xmit = SVAL(inbuf,smb_vwv0);
+
+ cnum = SVAL(inbuf,smb_vwv1);
+ }
+ else {
+ max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
+ if (max_xmit <= 0)
+ max_xmit = BUFFER_SIZE - 4;
+
+ cnum = SVAL(inbuf,smb_tid);
+ }
+ opt.max_xmit = max_xmit;
+ opt.tid = cnum;
+
+ DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
+
+ if (was_null)
+ {
+ free(inbuf);
+ free(outbuf);
+ }
+
+ if (options != NULL)
+ {
+ *options = opt;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+send a logout command
+****************************************************************************/
+void cli_send_logout(char *dum_in, char *dum_out)
+{
+ pstring inbuf,outbuf;
+
+ DEBUG(5,("cli_send_logout\n"));
+
+ bzero(outbuf,smb_size);
+ set_message(outbuf,0,0,True);
+ CVAL(outbuf,smb_com) = SMBtdis;
+ SSVAL(outbuf,smb_tid,cnum);
+ cli_setup_pkt(outbuf);
+
+ send_smb(Client,outbuf);
+ client_receive_smb(Client,inbuf,SHORT_TIMEOUT);
+
+ if (CVAL(inbuf,smb_rcls) != 0)
+ {
+ DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
+ }
+
+
+#ifdef STATS
+ stats_report();
+#endif
+ exit(0);
+}
+
+
+/****************************************************************************
+open the client sockets
+****************************************************************************/
+BOOL cli_open_sockets(int port )
+{
+ static int last_port;
+ char *host;
+ pstring service2;
+ extern int Client;
+
+ if (port == 0) port=last_port;
+ last_port=port;
+
+ strupper(service);
+
+ if (*desthost)
+ {
+ host = desthost;
+ }
+ else
+ {
+ pstrcpy(service2,service);
+ host = strtok(service2,"\\/");
+ if (!host) {
+ DEBUG(0,("Badly formed host name\n"));
+ return(False);
+ }
+ pstrcpy(desthost,host);
+ }
+
+ if (!(*global_myname)) {
+ get_myname(global_myname,NULL);
+ }
+ strupper(global_myname);
+
+ DEBUG(3,("Opening sockets\n"));
+
+ if (!have_ip)
+ {
+ if(!resolve_name( host, &dest_ip))
+ {
+ DEBUG(0,("cli_open_sockets: Unknown host %s.\n",host));
+ return False;
+ }
+ }
+
+ Client = open_socket_out(SOCK_STREAM, &dest_ip, port, LONG_CONNECT_TIMEOUT);
+ if (Client == -1)
+ return False;
+
+ DEBUG(3,("Connected\n"));
+
+ set_socket_options(Client,user_socket_options);
+
+ return True;
+}
+
+/****************************************************************************
+close and open the connection again
+****************************************************************************/
+BOOL cli_reopen_connection(char *inbuf,char *outbuf)
+{
+ static int open_count=0;
+
+ open_count++;
+
+ if (open_count>5) return(False);
+
+ DEBUG(1,("Trying to re-open connection\n"));
+
+ set_message(outbuf,0,0,True);
+ SCVAL(outbuf,smb_com,SMBtdis);
+ SSVAL(outbuf,smb_tid,cnum);
+ cli_setup_pkt(outbuf);
+
+ send_smb(Client,outbuf);
+ client_receive_smb(Client,inbuf,SHORT_TIMEOUT);
+
+ close_sockets();
+ if (!cli_open_sockets(0)) return(False);
+
+ return(cli_send_login(inbuf,outbuf,True,True,NULL));
+}
+
diff --git a/source/client/clitar.c b/source/client/clitar.c
index 1433ec59412..0f3d54fcc09 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,16 +19,54 @@
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;
+
+struct file_info_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;
+ char *name; /* This is dynamically allocate */
+
+ file_info2 *next, *prev; /* Used in the stack ... */
+
+};
-int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+typedef struct
+{
+ file_info2 *top;
+ int items;
+
+} stack;
+
+stack dir_stack = {NULL, 0}; /* Want an empty stack */
extern BOOL recurse;
@@ -46,17 +85,33 @@ static int attribute = aDIR | aSYSTEM | aHIDDEN;
#define CLIENT_TIMEOUT (30*1000)
#endif
-static char *tarbuf;
-static int tp, ntarf, tbufsiz;
+static char *tarbuf, *buffer_p;
+static int tp, ntarf, tbufsiz, 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;
@@ -71,47 +126,126 @@ 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);
+static int do_setrattr(char *fname, int attr, int setit);
+
/* 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
*/
+#if 0 /* Removed to get around gcc 'defined but not used' error. */
+
+/*
+ * Stack routines, push_dir, pop_dir, top_dir_name
+ */
+
+static BOOL push_dir(stack *tar_dir_stack, file_info2 *dir)
+{
+ dir -> next = tar_dir_stack -> top;
+ dir -> prev = NULL;
+ tar_dir_stack -> items++;
+ tar_dir_stack -> top = dir;
+ return(True);
+
+}
+
+static file_info2 *pop_dir(stack *tar_dir_stack)
+{
+ file_info2 *ptr;
+
+ ptr = tar_dir_stack -> top;
+ if (tar_dir_stack -> top != NULL) {
+
+ tar_dir_stack -> top = tar_dir_stack -> top -> next;
+ tar_dir_stack -> items--;
+
+ }
+
+ return ptr;
+
+}
+
+static char *top_dir_name(stack *tar_dir_stack)
+{
+
+ return(tar_dir_stack -> top != NULL?tar_dir_stack -> top -> name:NULL);
+
+}
+
+static BOOL sub_dir(char *dir1, char *dir2)
+{
+
+ return(True);
+
+}
+
+#endif /* Removed to get around gcc 'defined but not used' error. */
+
+/*******************************************************************
+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) {
+ /* 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+1, 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=%i, \n", b, strlen(b)));
+ dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
+ free(b);
+ }
/* use l + 1 to do the null too */
fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
@@ -122,14 +256,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 +276,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 +301,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 +371,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 +402,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 +410,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 +430,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 +445,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;
@@ -315,15 +474,18 @@ static void fixtarname(char *tptr, char *fp, int l)
* 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--;
+ int skip;
+ if((skip = skip_multibyte_char( *fp)) != 0) {
+ if (skip == 2) {
+ *tptr++ = *fp++;
+ *tptr++ = *fp++;
+ l -= 2;
+ } else if (skip == 1) {
+ *tptr++ = *fp++;
+ l--;
+ }
} else if (*fp == '\\') {
*tptr++ = '/';
fp++;
@@ -333,15 +495,12 @@ static void fixtarname(char *tptr, char *fp, int l)
l--;
}
}
-#else
- while (l--) { *tptr=(*fp == '\\') ? '/' : *fp; tptr++; fp++; }
-#endif
}
/****************************************************************************
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 +530,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 +540,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,12 +556,98 @@ int strslashcmp(const char *s1, const char *s2)
s1++; s2++;
}
+ /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
+ string of s2.
+ */
+ if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
+
+ /* ignore trailing slash on s1 */
+ if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
+
+ /* check for s1 is an "initial" string of s2 */
+ if (*s2 == '/' || *s2 == '\\') return 0;
+
return *s1-*s2;
}
/*
* general smb utility functions
*/
+/**********************************************************************
+do_setrtime, set time on a file or dir ...
+**********************************************************************/
+
+static int do_setrtime(char *fname, int mtime, BOOL err_silent)
+{
+ char *inbuf, *outbuf, *p;
+ char *name;
+
+ DEBUG(5, ("Setting time on: %s, fnlen=%i.\n", fname, strlen(fname)));
+
+ name = (char *)malloc(strlen(fname) + 1 + 1);
+ if (name == NULL) {
+
+ DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname));
+ return False;
+
+ }
+
+ if (*fname != '\\')
+ safe_strcpy(name, "\\", strlen(fname) + 1);
+ else
+ safe_strcpy(name, "", strlen(fname) + 1);
+ safe_strcat(name, fname, strlen(fname) + 1);
+
+ if (fname[strlen(name) - 1] == '\\')
+ name[strlen(name) - 1] = '\0';
+
+ inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+ if (!inbuf || !outbuf) {
+
+ DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname));
+ free(name);
+ return False;
+
+ }
+
+ memset(outbuf, 0, smb_size);
+ set_message(outbuf, 8, 4 + strlen(name), True);
+ CVAL(outbuf, smb_com) = SMBsetatr;
+ SSVAL(outbuf, smb_tid, cnum);
+ cli_setup_pkt(outbuf);
+
+ SSVAL(outbuf, smb_vwv0, 0);
+ put_dos_date3(outbuf, smb_vwv1, mtime);
+
+ p = smb_buf(outbuf);
+ *p++ = 4;
+ safe_strcpy(p, name, strlen(name));
+ p+= (strlen(fname)+1);
+
+ *p++ = 4;
+ *p++ = 0;
+
+ send_smb(Client, outbuf);
+ client_receive_smb(Client, inbuf, CLIENT_TIMEOUT);
+
+ if (CVAL(inbuf,smb_rcls) != 0)
+ {
+ if (!err_silent) {
+ DEBUG(0,("%s setting attributes on file %s\n",
+ smb_errstr(inbuf), fname));
+ }
+ free(name);free(inbuf);free(outbuf);
+ return(False);
+ }
+
+ free(name);
+ free(inbuf);free(outbuf);
+ return(True);
+
+}
+
/****************************************************************************
Set DOS file attributes
***************************************************************************/
@@ -409,12 +658,19 @@ static int do_setrattr(char *fname, int attr, int setit)
*/
char *inbuf,*outbuf;
char *p;
- pstring name;
+ char *name;
int fattr;
- strcpy(name,fname);
- strcpy(fname,"\\");
- strcat(fname,name);
+ name = (char *)malloc(strlen(fname) + 1 + 1);
+ if (name == NULL) {
+
+ DEBUG(0, ("Failed to allocate space in do_setrattr while setting time on file: %s", fname));
+ return False;
+
+ }
+
+ safe_strcpy(name, "\\", strlen(fname) + 1);
+ safe_strcat(name, fname, strlen(fname) + 1);
inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -422,6 +678,7 @@ static int do_setrattr(char *fname, int attr, int setit)
if (!inbuf || !outbuf)
{
DEBUG(0,("out of memory\n"));
+ free(name);
return False;
}
@@ -431,18 +688,18 @@ static int do_setrattr(char *fname, int attr, int setit)
set_message(outbuf,0,2 + strlen(fname),True);
CVAL(outbuf,smb_com) = SMBgetatr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,fname);
- p += (strlen(fname)+1);
+ safe_strcpy(p,name, strlen(name));
+ p += (strlen(name)+1);
*p++ = 4;
*p++ = 0;
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
@@ -464,32 +721,33 @@ static int do_setrattr(char *fname, int attr, int setit)
/* clear out buffer and start again */
memset(outbuf,0,smb_size);
- set_message(outbuf,8,4 + strlen(fname),True);
+ set_message(outbuf,8,4 + strlen(name),True);
CVAL(outbuf,smb_com) = SMBsetatr;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,attr);
-
+
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,fname);
- p += (strlen(fname)+1);
+ safe_strcpy(p,name, strlen(name));
+ p += (strlen(name)+1);
*p++ = 4;
*p++ = 0;
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_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);
+ smb_errstr(inbuf), name));
+ free(name);free(inbuf);free(outbuf);
return(False);
}
+ free(name);
free(inbuf);free(outbuf);
return(True);
}
@@ -497,27 +755,27 @@ static int do_setrattr(char *fname, int attr, int setit)
/****************************************************************************
Create a file on a share
***************************************************************************/
-static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
+static BOOL smbcreat(file_info2 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);
+ cli_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);
+ safe_strcpy(p,finfo.name, strlen(finfo.name));
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -546,7 +804,7 @@ static BOOL smbwrite(int fnum, int n, int low, int high, int left,
set_message(outbuf,5,n + 3, False);
CVAL(outbuf,smb_com) = SMBwrite;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,n);
@@ -556,7 +814,7 @@ static BOOL smbwrite(int fnum, int n, int low, int high, int left,
SSVAL(smb_buf(outbuf),1,n);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -577,7 +835,7 @@ static BOOL smbwrite(int fnum, int n, int low, int high, int left,
/****************************************************************************
Close a file on a share
***************************************************************************/
-static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
+static BOOL smbshut(file_info2 finfo, int fnum, char *inbuf, char *outbuf)
{
/* *must* be called with buffer ready malloc'ed */
@@ -585,17 +843,17 @@ static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
set_message(outbuf,3,0,True);
CVAL(outbuf,smb_com) = SMBclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_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)),
+ DEBUG(3,("Setting date to %s (0x%lX)",
+ asctime(LocalTime(&finfo.mtime)),
finfo.mtime));
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -618,14 +876,14 @@ static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
set_message(outbuf,0,4 + strlen(fname),True);
CVAL(outbuf,smb_com) = SMBchkpth;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,fname);
+ safe_strcpy(p,fname, strlen(fname));
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
@@ -645,14 +903,14 @@ static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
CVAL(outbuf,smb_com) = SMBmkdir;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
p = smb_buf(outbuf);
*p++ = 4;
- strcpy(p,fname);
+ safe_strcpy(p,fname, strlen(fname));
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -672,14 +930,26 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
/* *must* be called with buffer ready malloc'ed */
/* ensures path exists */
- pstring partpath, ffname;
+ char *partpath, *ffname;
char *p=fname, *basehack;
+ DEBUG(5, ( "Ensurepath called with: %s\n", fname));
+
+ partpath = string_create_s(strlen(fname));
+ ffname = string_create_s(strlen(fname));
+
+ if ((partpath == NULL) || (ffname == NULL)){
+
+ DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
+ return(False);
+
+ }
+
*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)
@@ -691,7 +961,7 @@ 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))
@@ -704,13 +974,29 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
}
- strcat(partpath, "\\");
+ safe_strcat(partpath, "\\", strlen(fname) + 1);
p = strtok(NULL,"/\\");
}
return True;
}
+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;
+}
+
/*
* smbclient functions
*/
@@ -721,9 +1007,9 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
{
int fnum;
uint32 nread=0;
- char *p;
+ char *p, ftype;
char *inbuf,*outbuf;
- file_info finfo;
+ file_info2 finfo;
BOOL close_done = False;
BOOL shallitime=True;
BOOL ignore_close_error = False;
@@ -733,11 +1019,38 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
struct timeval tp_start;
GetTimeOfDay(&tp_start);
- if (finfo1)
- finfo = *finfo1;
- else
- finfo = def_finfo;
+ ftype = '0'; /* An ordinary file ... */
+
+ 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 (dry_run)
+ {
+ DEBUG(3,("skipping file %s of size %d bytes\n",
+ finfo.name,
+ finfo.size));
+ shallitime=0;
+ ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
+ ntarf++;
+ return;
+ }
+
inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -752,7 +1065,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
CVAL(outbuf,smb_com) = SMBopenX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0xFF);
SSVAL(outbuf,smb_vwv2,1);
@@ -762,7 +1075,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
SSVAL(outbuf,smb_vwv8,1);
p = smb_buf(outbuf);
- strcpy(p,rname);
+ safe_strcpy(p, rname, strlen(rname));
p = skip_string(p,1);
dos_clean_name(rname);
@@ -774,7 +1087,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
memset(p,0,200);
p -= smb_wct;
- SSVAL(p,smb_wct,10);
+ SCVAL(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));
@@ -782,13 +1095,13 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
}
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_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))
+ cli_reopen_connection(inbuf,outbuf))
{
do_atar(rname,lname,finfo1);
free(inbuf);free(outbuf);
@@ -800,7 +1113,16 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
return;
}
- strcpy(finfo.name,rname);
+ finfo.name = string_create_s(strlen(rname));
+ if (finfo.name == NULL) {
+
+ DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
+ free(inbuf); free(outbuf);
+ return;
+
+ }
+
+ safe_strcpy(finfo.name,rname, strlen(rname));
if (!finfo1)
{
finfo.mode = SVAL(inbuf,smb_vwv3);
@@ -818,6 +1140,16 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
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)
@@ -832,13 +1164,13 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
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,
lname));
/* write a tar header, don't bother with mode - just set to 100644 */
- writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0");
+ writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
while (nread < finfo.size && !close_done)
{
@@ -884,7 +1216,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,10,0,True);
CVAL(outbuf,smb_com) = SMBreadX;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
if (close_done)
{
@@ -916,7 +1248,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
}
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -950,7 +1282,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,8,0,True);
CVAL(outbuf,smb_com) = SMBreadbraw;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SIVAL(outbuf,smb_vwv1,nread);
SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
@@ -1002,7 +1334,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,5,0,True);
CVAL(outbuf,smb_com) = SMBread;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
@@ -1010,7 +1342,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
SSVAL(outbuf,smb_vwv4,finfo.size - nread);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
@@ -1028,7 +1360,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
* write out in 512 byte intervals */
if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
{
- DEBUG(0,("Error writing local file\n"));
+ DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
break;
}
@@ -1042,11 +1374,20 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
dataptr=NULL;
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", finfo.size, nread));
+ if (padit(inbuf, BUFFER_SIZE, 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++;
}
@@ -1056,13 +1397,13 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
set_message(outbuf,3,0,True);
CVAL(outbuf,smb_com) = SMBclose;
SSVAL(outbuf,smb_tid,cnum);
- setup_pkt(outbuf);
+ cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,fnum);
SIVALS(outbuf,smb_vwv1,-1);
send_smb(Client,outbuf);
- receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+ client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
{
@@ -1078,7 +1419,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,8 +1429,15 @@ 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",
+ 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))));
}
@@ -1103,25 +1452,29 @@ static void do_tar(file_info *finfo)
{
pstring rname;
- if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+ if (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) = %i\n", 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, False))) {
+#endif
DEBUG(3,("Skipping file %s\n", exclaim));
return;
}
@@ -1142,25 +1495,34 @@ static void do_tar(file_info *finfo)
return;
}
- strcpy(saved_curdir,cur_dir);
+ safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
+
+ DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
- strcat(cur_dir,finfo->name);
- strcat(cur_dir,"\\");
+ safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
+ safe_strcat(cur_dir,"\\", sizeof(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);
+ 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));
+ /* do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */
+ safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
free(inbuf);free(outbuf);
}
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,24 +1530,36 @@ 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.
+ * dos \'s in path. Kill any absolute path names. But only if first!
*/
- if (*fp == '.') fp++;
- if (*fp == '\\' || *fp == '/') fp++;
+ DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
-#ifdef KANJI
- while (l > 0) {
- if (is_shift_jis (*fp)) {
- *tptr++ = *fp++;
- *tptr++ = *fp++;
- l -= 2;
- } else if (is_kana (*fp)) {
- *tptr++ = *fp++;
+ if (first) {
+ if (*fp == '.') {
+ fp++;
+ l--;
+ }
+ if (*fp == '\\' || *fp == '/') {
+ fp++;
l--;
+ }
+ }
+
+ while (l > 0) {
+ int skip;
+ if(( skip = skip_multibyte_char( *fp )) != 0) {
+ if (skip == 2) {
+ *tptr++ = *fp++;
+ *tptr++ = *fp++;
+ l -= 2;
+ } else if (skip == 1) {
+ *tptr++ = *fp++;
+ l--;
+ }
} else if (*fp == '/') {
*tptr++ = '\\';
fp++;
@@ -1195,21 +1569,426 @@ static void unfixtarname(char *tptr, char *fp, int l)
l--;
}
}
+}
+
+#ifndef OLD_DOTARPUT
+
+/****************************************************************************
+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: %0x\n", (unsigned int)*bufferp));
+ *bufferp += TBLOCK;
+ total = TBLOCK;
+
+ if (*bufferp >= (ltarbuf + bufsiz)) {
+
+ DEBUG(5, ("Reading more data into ltarbuf ...\n"));
+
+ total = 0;
+
+ for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
+
+ if (bufread <= 0) { /* An error, return false */
+ return (total > 0 ? -2 : bufread);
+ }
+
+ }
+
+ DEBUG(5, ("Total bytes read ... %i\n", total));
+
+ *bufferp = ltarbuf;
+
+ }
+
+ return(total);
+
+}
+
+/* Skip a file, even if it includes a long file name? */
+static int skip_file(int skipsize)
+{
+ 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);
+}
+
+/* We get a file from the tar file and store it */
+static int get_file(file_info2 finfo, char * inbuf, char * outbuf)
+{
+ int fsize = finfo.size;
+ int fnum, pos = 0, dsize = 0, rsize = 0, bpos = 0;
+
+ DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
+
+ if (ensurepath(finfo.name, inbuf, outbuf) &&
+ !smbcreat(finfo, &fnum, inbuf, outbuf))
+ {
+ DEBUG(0, ("abandoning restore\n"));
+ return(False);
+ }
+
+ /* read the blocks from the tar file and write to the remote file */
+
+ rsize = fsize; /* 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, max_xmit - 50); /* Calculate the size to write */
+ dsize = MIN(dsize, rsize); /* Should be only what is left */
+ DEBUG(5, ("writing %i bytes, max_xmit = %i, bpos = %i ...\n", dsize, max_xmit, bpos));
+
+ if (!smbwrite(fnum, dsize, pos, 0, fsize - pos, buffer_p + bpos, inbuf, outbuf)) {
+
+ 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;
+
+ }
+
+ }
+
+ while (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 (!smbshut(finfo, fnum, inbuf, outbuf)) {
+
+ 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 (!do_setrtime(finfo.name, finfo.mtime, True)) {
+
+ 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, 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, char * inbuf, char * outbuf)
+{
+
+ DEBUG(5, ("Creating directory: %s\n", finfo.name));
+
+ if (!ensurepath(finfo.name, inbuf, outbuf)) {
+
+ DEBUG(0, ("Problems creating directory\n"));
+ return(False);
+
+ }
+ 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 = %i\n", finfo.size));
+
+ if (longname == NULL) {
+
+ DEBUG(0, ("could not allocate buffer of size %d for longname\n",
+ 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;
+ char *inbuf, *outbuf, *longfilename = NULL, linkflag;
+ int skip = False;
+
+ GetTimeOfDay(&tp_start);
+
+ DEBUG(5, ("RJS do_tarput called ...\n"));
+
+ buffer_p = tarbuf + tbufsiz; /* init this to force first read */
+
+#if 0 /* Fix later ... */
+ if (push_dir(&dir_stack, &finfo)) {
+ file_info2 *finfo2;
+
+ finfo2 = pop_dir(&dir_stack);
+ inbuf = top_dir_name(&dir_stack); /* FIXME */
+ if (sub_dir(inbuf, finfo2 -> name)){
+
+ DEBUG(0, (""));
+
+ }
+ }
+#endif
+
+ inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+ if (!inbuf || !outbuf) {
+
+ DEBUG(0, ("Out of memory during allocate of inbuf and outbuf!\n"));
+ return;
+
+ }
+
+ /* 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;
+
+ }
+
+ DEBUG(5, ("Reading the next header ...\n"));
+
+ 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)) {
+
+ DEBUG(0, ("Short file, bailing out...\n"));
+ free(inbuf); free(outbuf);
+ return;
+
+ }
+
+ break;
+
+ case -1:
+ DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
+ free(inbuf); free(outbuf);
+ return;
+
+ case 0: /* chksum is zero - looks like an EOF */
+ DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
+ free(inbuf); free(outbuf);
+ return; /* Hmmm, bad here ... */
+
+ default:
+ /* No action */
+
+ break;
+
+ }
+
+ /* Now, do we have a long file name? */
+
+ if (longfilename != NULL) {
+
+ free(finfo.name); /* Free the space already allocated */
+ finfo.name = longfilename;
+ longfilename = NULL;
+
+ }
+
+ /* Well, now we have a header, process the file ... */
+
+ /* 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
- while (l--) { *tptr=(*fp == '/') ? '\\' : *fp; tptr++; fp++; }
+ || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
#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 ... */
+
+ if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ DEBUG(0, ("Short file, bailing out...\n"));
+ free(inbuf); free(outbuf);
+ return;
+ }
+ if (!get_file(finfo, inbuf, outbuf)) {
+
+ free(inbuf); free(outbuf);
+ DEBUG(0, ("Abandoning restore\n"));
+ return;
+
+ }
+ break;
+
+ case '5':
+ if (!get_dir(finfo, inbuf, outbuf)) {
+ free(inbuf); free(outbuf);
+ DEBUG(0, ("Abandoning restore \n"));
+ return;
+ }
+ break;
+
+ case 'L':
+ longfilename = get_longfilename(finfo);
+ if (!longfilename) {
+ free(inbuf); free(outbuf);
+ 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;
+
+ }
+
+ }
+
+
}
+#else
+
static void do_tarput()
{
- file_info finfo;
+ file_info2 finfo;
int nread=0, bufread;
- char *inbuf,*outbuf;
+ char *inbuf,*outbuf, *longname = NULL;
int fsize=0;
int fnum;
struct timeval tp_start;
BOOL tskip=False; /* We'll take each file as it comes */
+ finfo.name = NULL; /* No name in here ... */
+
GetTimeOfDay(&tp_start);
inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -1227,7 +2006,7 @@ static void do_tarput()
/* These should be the only reads in clitar.c */
while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
- char *bufferp, *endofbuffer;
+ char *endofbuffer;
int chunk;
/* Code to handle a short read.
@@ -1249,13 +2028,13 @@ static void do_tarput()
if (lread<=0) break;
}
- bufferp=tarbuf;
+ buffer_p=tarbuf;
endofbuffer=tarbuf+bufread;
if (tskip) {
if (fsize<bufread) {
tskip=False;
- bufferp+=fsize;
+ buffer_p+=fsize;
fsize=0;
} else {
if (fsize==bufread) tskip=False;
@@ -1267,57 +2046,175 @@ static void do_tarput()
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;
+ int next_header = 1; /* Want at least one header */
+ while (next_header)
+ {
+ if (buffer_p >= endofbuffer) {
+
+ bufread = read(tarhandle, tarbuf, tbufsiz);
+ buffer_p = tarbuf;
+
+ }
+ next_header = 0; /* Don't want the next one ... */
+
+ if (finfo.name != NULL) { /* Free the space */
+
+ free(finfo.name);
+ finfo.name = NULL;
+
}
+ DEBUG(5, ("Tarbuf=%X, buffer=%X, endofbuf=%X\n",
+ (int)tarbuf, (int)buffer_p, (int)endofbuffer));
+ switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir))
+ {
+ case -2: /* something dodgy but not fatal about this */
+ DEBUG(0, ("skipping %s...\n", finfo.name));
+ buffer_p+=TBLOCK; /* header - like a link */
+ continue;
+ case -1:
+ DEBUG(0, ("abandoning restore, -1 from readtarheader\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;
+ }
+
+ /* If we have a longname left from the last time through,
+ copy it into finfo.name and free it.
+
+ The size of a pstring is the limiting factor on filenames
+ and directory names now. The total pathname length must be
+ less than sizeof(pstring) - 1, which is currently 1023. */
+
+ if (longname != NULL) {
+
+ free(finfo.name); /* Free the name in the finfo */
+ finfo.name = string_create_s(strlen(longname) + 2);
+ strncpy(finfo.name, longname, strlen(longname) + 1);
+ DEBUG(5, ("Long name = \"%s\", filename=\"%s\"\n", longname, finfo.name));
+ free(longname);
+ longname = NULL;
+
+ }
+
+ /* Check if a long-link. We do this before the clip checking
+ because clip-checking should clip on real name - RJS */
+
+ if (((union hblock *)buffer_p) -> dbuf.linkflag == 'L') {
+ int file_len, first = 0; char *cp;
+
+ /* Skip this header, but pick up length, get the name and
+ fix the name and skip the name. Hmmm, what about end of
+ buffer??? */
+ longname = malloc(finfo.size + strlen(cur_dir) + 1);
+ if (longname == NULL) {
+
+ DEBUG(0, ("could not allocate buffer of size %d for longname\n",
+ finfo.size + strlen(cur_dir) + 1)
+ );
+ free(inbuf); free(outbuf);
+ return;
+ }
+
+
+ bzero(longname, finfo.size + strlen(cur_dir) +1);
+
+ buffer_p += TBLOCK; /* Skip that longlink header */
+
+ /* This needs restructuring ... */
+
+ safe_strcpy(longname, cur_dir, strlen(cur_dir) + 1);
+ cp = longname + strlen(cur_dir);
+ file_len = finfo.size;
+
+ DEBUG(5, ("longname=%0X, cp=%0X, file_len=%i\n",
+ (int)longname, (int)cp, file_len));
+
+ while (file_len > 0) {
+
+ if (buffer_p >= endofbuffer) {
+
+ bufread = read(tarhandle, tarbuf, tbufsiz);
+
+ buffer_p = tarbuf;
+
+ }
+
+ unfixtarname(cp, buffer_p, file_len >= TBLOCK?TBLOCK:file_len, first == 0);
+
+ first++; /* Not the first anymore */
+ cp = cp + strlen(cp); /* Move to end of string */
+ buffer_p += TBLOCK;
+ file_len -= TBLOCK;
+ DEBUG(5, ("cp=%0X, file_len=%i\n", (int)cp, file_len));
+ next_header = 1; /* Force read of next header */
+
+ }
+ }
+ }
tskip=clipn
- && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl);
+ && ((!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, False)));
+#endif
if (tskip) {
- bufferp+=TBLOCK;
+ buffer_p+=TBLOCK;
if (finfo.mode & aDIR)
continue;
else if ((fsize=finfo.size) % TBLOCK) {
fsize+=TBLOCK-(fsize%TBLOCK);
}
- if (fsize<endofbuffer-bufferp) {
- bufferp+=fsize;
+ if (fsize<endofbuffer-buffer_p) {
+ buffer_p+=fsize;
fsize=0;
continue;
} else {
- fsize-=endofbuffer-bufferp;
+ fsize-=endofbuffer-buffer_p;
break;
}
}
+ DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
+
if (finfo.mode & aDIR)
{
- if (!smbchkpath(finfo.name, inbuf, outbuf)
- && !smbmkdir(finfo.name, inbuf, outbuf))
+
+ DEBUG(5, ("Creating directory: %s\n", finfo.name));
+ DEBUG(0, ("restore tar dir %s of size %d bytes\n",
+ finfo.name, finfo.size));
+
+ if (!ensurepath(finfo.name, inbuf, outbuf))
{
- DEBUG(0, ("abandoning restore\n"));
+ DEBUG(0, ("abandoning restore, problems ensuring path\n"));
free(inbuf); free(outbuf);
return;
}
else
{
- bufferp+=TBLOCK;
+ /* Now we update the creation date ... */
+
+ DEBUG(5, ("Updating creation date on %s\n", finfo.name));
+
+ if (!do_setrtime(finfo.name, finfo.mtime, True)) {
+
+ if (tar_real_noisy) {
+ DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
+ }
+ /*return; - Win 95 does not like setting time on dirs */
+
+ }
+
+ ntarf++;
+ buffer_p+=TBLOCK;
continue;
}
}
@@ -1332,17 +2229,25 @@ static void do_tarput()
return;
}
- DEBUG(0,("restore tar file %s of size %d bytes\n",
- finfo.name,finfo.size));
+ DEBUG(0 ,("restore tar file %s of size %d bytes\n",
+ finfo.name, finfo.size));
+
+ /* if (!finfo.size) {
+ if (!smbshut(finfo, fnum, inbuf, outbuf)){
+ DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
+ free(inbuf);free(outbuf);
+ return;
+ }
+ } */
nread=0;
- if ((bufferp+=TBLOCK) >= endofbuffer) break;
+ if ((buffer_p+=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;
+ chunk=(fsize-nread < endofbuffer - buffer_p)
+ ? fsize - nread : endofbuffer - buffer_p;
while (chunk > 0) {
int minichunk=MIN(chunk, max_xmit-200);
@@ -1352,7 +2257,7 @@ static void do_tarput()
nread, /* offset low */
0, /* offset high - not implemented */
fsize-nread, /* left - only hint to server */
- bufferp,
+ buffer_p,
inbuf,
outbuf))
{
@@ -1362,10 +2267,10 @@ static void do_tarput()
}
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;
+ buffer_p+=minichunk; nread+=minichunk;
chunk-=minichunk;
}
-
+
if (nread>=fsize)
{
if (!smbshut(finfo, fnum, inbuf, outbuf))
@@ -1374,13 +2279,14 @@ static void do_tarput()
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)));
+ if (fsize % TBLOCK) buffer_p+=TBLOCK - (fsize % TBLOCK);
+ DEBUG(5, ("buffer_p is now %d (psn=%d)\n",
+ (int) buffer_p, (int)(buffer_p - tarbuf)));
ntarf++;
fsize=0;
+
}
- } while (bufferp < endofbuffer);
+ } while (buffer_p < endofbuffer);
}
DEBUG(0, ("premature eof on tar file ?\n"));
@@ -1388,6 +2294,7 @@ static void do_tarput()
free(inbuf); free(outbuf);
}
+#endif
/*
* samba interactive commands
@@ -1396,12 +2303,12 @@ static void do_tarput()
/****************************************************************************
Blocksize command
***************************************************************************/
-void cmd_block(void)
+void cmd_block(char *dum_in, char *dum_out)
{
fstring buf;
int block;
- if (!next_token(NULL,buf,NULL))
+ if (!next_token(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0, ("blocksize <n>\n"));
return;
@@ -1421,11 +2328,11 @@ void cmd_block(void)
/****************************************************************************
command to set incremental / reset mode
***************************************************************************/
-void cmd_tarmode(void)
+void cmd_tarmode(char *dum_in, char *dum_out)
{
fstring buf;
- while (next_token(NULL,buf,NULL)) {
+ while (next_token(NULL,buf,NULL,sizeof(buf))) {
if (strequal(buf, "full"))
tar_inc=False;
else if (strequal(buf, "inc"))
@@ -1434,18 +2341,34 @@ 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"));
+
}
/****************************************************************************
Feeble attrib command
***************************************************************************/
-void cmd_setmode(void)
+void cmd_setmode(char *dum_in, char *dum_out)
{
char *q;
fstring buf;
@@ -1455,16 +2378,16 @@ void cmd_setmode(void)
attra[0] = attra[1] = 0;
- if (!next_token(NULL,buf,NULL))
+ if (!next_token(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
return;
}
- 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(NULL,buf,NULL,sizeof(buf))) {
q=buf;
while(*q)
@@ -1492,7 +2415,7 @@ void cmd_setmode(void)
return;
}
-DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
+ 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);
}
@@ -1506,9 +2429,9 @@ void cmd_tar(char *inbuf, char *outbuf)
char **argl;
int argcl;
- if (!next_token(NULL,buf,NULL))
+ if (!next_token(NULL,buf,NULL,sizeof(buf)))
{
- DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
+ DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
return;
}
@@ -1529,7 +2452,12 @@ int process_tar(char *inbuf, char *outbuf)
initarbuf();
switch(tar_type) {
case 'x':
+
+#if 0
+ do_tarput2();
+#else
do_tarput();
+#endif
free(tarbuf);
close(tarhandle);
break;
@@ -1540,7 +2468,7 @@ 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';
@@ -1549,30 +2477,30 @@ int process_tar(char *inbuf, char *outbuf)
if (strrchr(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);
+ safe_strcpy(cur_dir, tarmac, sizeof(pstring));
*(strrchr(cur_dir, '\\')+1)='\0';
- do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
- strcpy(cur_dir,saved_dir);
+ do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, 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));
+ do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, 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));
+ safe_strcat(mask,"\\*", sizeof(pstring));
+ do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
}
if (ntarf) dotareof(tarhandle);
@@ -1580,16 +2508,28 @@ int process_tar(char *inbuf, char *outbuf)
free(tarbuf);
DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
+ DEBUG(0, ("Total bytes written: %d\n", ttarf));
break;
}
+ if (must_free_cliplist) {
+ int i;
+ for (i = 0; i < clipn; ++i) {
+ free(cliplist[i]);
+ }
+ 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;
@@ -1609,6 +2549,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)
+{
+ FILE *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 = fopen(filename, "r")) == 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) && (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) {
+ inclusion_buffer_size *= 2;
+ inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
+ if (! inclusion_buffer) {
+ DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
+ inclusion_buffer_size));
+ error = 1;
+ break;
+ }
+ }
+
+ safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
+ inclusion_buffer_sofar += strlen(buf) + 1;
+ clipn++;
+ }
+ 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(p, '\000')) == NULL) {
+ DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
+ abort();
+ }
+ }
+ ++p;
+ }
+ must_free_cliplist = True;
+ }
+ }
+
+ if (inclusion_buffer) {
+ free(inclusion_buffer);
+ }
+ if (error) {
+ if (cliplist) {
+ char **pp;
+ /* We know cliplist is always null-terminated */
+ for (pp = cliplist; *pp; ++pp) {
+ free(*pp);
+ }
+ 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 +2668,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 +2698,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) {
+ if (dos_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"));
@@ -1668,18 +2717,38 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
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 +2759,99 @@ 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');
} else {
- tar_excl=tar_clipfl!='X';
-
- if (Optind+1<argc) {
- cliplist=argv+Optind+1;
- clipn=argc-Optind-1;
- }
-
+ 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 = open(argv[Optind], O_RDONLY)) == -1)
|| (tar_type=='c' && (tarhandle=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..fa3cacb8640
--- /dev/null
+++ b/source/client/smbmnt.c
@@ -0,0 +1,285 @@
+/*
+ * smbmount.c
+ *
+ * Copyright (C) 1995-1998 by Paal-Kr. Engstad and 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 <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 char *progname;
+
+
+static void
+usage(void)
+{
+ printf("usage: %s mount-point [options]\n", progname);
+ printf("Try `%s -h' for more information\n", progname);
+}
+
+static void
+help(void)
+{
+ printf("\n");
+ printf("usage: %s mount-point [options]\n", progname);
+ printf("-u uid uid the mounted files get\n"
+ "-g gid gid the mounted files get\n"
+ "-f mode permission the files get (octal notation)\n"
+ "-d mode permission the dirs get (octal notation)\n"
+ "-P pid connection handler's pid\n\n"
+ "-s share share name on server\n\n"
+ "-h print this help text\n");
+}
+
+static int
+parse_args(int argc, char *argv[], struct smb_mount_data *data, char **share)
+{
+ int opt;
+ struct passwd *pwd;
+ struct group *grp;
+
+ while ((opt = getopt (argc, argv, "u:g:f:d:s:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'u':
+ if (isdigit(optarg[0]))
+ {
+ data->uid = atoi(optarg);
+ }
+ else
+ {
+ pwd = getpwnam(optarg);
+ if (pwd == NULL)
+ {
+ fprintf(stderr, "Unknown user: %s\n",
+ optarg);
+ return 1;
+ }
+ data->uid = pwd->pw_uid;
+ }
+ break;
+ case 'g':
+ if (isdigit(optarg[0]))
+ {
+ data->gid = atoi(optarg);
+ }
+ else
+ {
+ grp = getgrnam(optarg);
+ if (grp == NULL)
+ {
+ fprintf(stderr, "Unknown group: %s\n",
+ optarg);
+ return 1;
+ }
+ data->gid = grp->gr_gid;
+ }
+ break;
+ case 'f':
+ data->file_mode = strtol(optarg, NULL, 8);
+ break;
+ case 'd':
+ data->dir_mode = strtol(optarg, NULL, 8);
+ break;
+ case 's':
+ *share = 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)
+ {
+ return strdup(p);
+ }
+ return strdup(path);
+}
+
+/* Check whether user is allowed to mount on the specified mount point */
+static int
+mount_ok(SMB_STRUCT_STAT *st)
+{
+ if (!S_ISDIR(st->st_mode))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ if ( (getuid() != 0)
+ && ( (getuid() != st->st_uid)
+ || ((st->st_mode & S_IRWXU) != S_IRWXU)))
+ {
+ errno = EPERM;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *mount_point, *share_name = NULL;
+ FILE *mtab;
+ int fd, um;
+ unsigned int flags;
+ struct smb_mount_data data;
+ SMB_STRUCT_STAT st;
+ struct mntent ment;
+
+ progname = argv[0];
+
+ memset(&data, 0, sizeof(struct smb_mount_data));
+
+ if ( (argc == 2)
+ && (argv[1][0] == '-')
+ && (argv[1][1] == 'h')
+ && (argv[1][2] == '\0'))
+ {
+ help();
+ return 0;
+ }
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s must be installed suid root\n", progname);
+ exit(1);
+ }
+
+ if (argc < 2)
+ {
+ usage();
+ return 1;
+ }
+
+ mount_point = argv[1];
+
+ argv += 1;
+ argc -= 1;
+
+ if (sys_stat(mount_point, &st) == -1) {
+ fprintf(stderr, "could not find mount point %s: %s\n",
+ mount_point, strerror(errno));
+ exit(1);
+ }
+
+ if (mount_ok(&st) != 0) {
+ fprintf(stderr, "cannot 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();
+
+ data.uid = getuid();
+ data.gid = getgid();
+ um = umask(0);
+ umask(um);
+ data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
+ data.dir_mode = 0;
+
+ if (parse_args(argc, argv, &data, &share_name) != 0) {
+ usage();
+ return -1;
+ }
+
+ if (data.dir_mode == 0) {
+ data.dir_mode = data.file_mode;
+ if ((data.dir_mode & S_IRUSR) != 0)
+ data.dir_mode |= S_IXUSR;
+ if ((data.dir_mode & S_IRGRP) != 0)
+ data.dir_mode |= S_IXGRP;
+ if ((data.dir_mode & S_IROTH) != 0)
+ data.dir_mode |= S_IXOTH;
+ }
+
+ flags = MS_MGC_VAL;
+
+ if (mount(share_name, mount_point, "smbfs", flags, (char *)&data) < 0)
+ {
+ perror("mount error");
+ printf("Please refer to the smbmnt(8) manual page\n");
+ return -1;
+ }
+
+ ment.mnt_fsname = share_name ? share_name : "none";
+ ment.mnt_dir = fullpath(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..dadccc819d1
--- /dev/null
+++ b/source/client/smbmount.c
@@ -0,0 +1,843 @@
+/*
+ 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.
+*/
+
+#define NO_SYSLOG
+
+#include <linux/version.h>
+#define LVERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
+#if LINUX_VERSION_CODE < LVERSION(2,1,70)
+#error this code will only compile on versions of linux after 2.1.70
+#endif
+
+#include "includes.h"
+
+#include <asm/types.h>
+#include <linux/smb_fs.h>
+static struct smb_conn_opt conn_options;
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+/* Uncomment this to allow debug the smbmount daemon */
+#define SMBFS_DEBUG 1
+
+pstring cur_dir = "\\";
+pstring cd_path = "";
+extern pstring service;
+extern pstring desthost;
+extern pstring global_myname;
+extern pstring myhostname;
+extern pstring password;
+extern pstring username;
+extern pstring workgroup;
+char *cmdstr="";
+extern BOOL got_pass;
+extern BOOL connect_as_printer;
+extern BOOL connect_as_ipc;
+extern struct in_addr ipzero;
+
+extern BOOL doencrypt;
+
+extern pstring user_socket_options;
+
+/* 30 second timeout on most commands */
+#define CLIENT_TIMEOUT (30*1000)
+#define SHORT_TIMEOUT (5*1000)
+
+/* value for unused fid field in trans2 secondary request */
+#define FID_UNUSED (0xFFFF)
+
+extern int name_type;
+
+extern int max_protocol;
+int port = SMB_PORT;
+
+
+time_t newer_than = 0;
+int archive_level = 0;
+
+extern pstring debugf;
+extern int DEBUGLEVEL;
+
+BOOL translation = False;
+
+extern int cnum;
+extern int mid;
+extern int pid;
+extern int tid;
+extern int gid;
+extern int uid;
+
+extern BOOL have_ip;
+extern int max_xmit;
+
+/* clitar bits insert */
+extern int blocksize;
+extern BOOL tar_inc;
+extern BOOL tar_reset;
+/* clitar bits end */
+
+
+int myumask = 0755;
+
+extern pstring scope;
+
+BOOL prompt = True;
+
+int printmode = 1;
+
+BOOL recurse = False;
+BOOL lowercase = False;
+
+struct in_addr dest_ip;
+
+#define SEPARATORS " \t\n\r"
+
+BOOL abort_mget = True;
+
+extern int Protocol;
+
+extern BOOL readbraw_supported ;
+extern BOOL writebraw_supported;
+
+pstring fileselection = "";
+
+extern file_info def_finfo;
+
+/* timing globals */
+int get_total_size = 0;
+int get_total_time_ms = 0;
+int put_total_size = 0;
+int put_total_time_ms = 0;
+
+/* totals globals */
+int dir_total = 0;
+
+extern int Client;
+
+#define USENMB
+
+#define CNV_LANG(s) dos_to_unix(s,False)
+#define CNV_INPUT(s) unix_to_dos(s,True)
+
+/****************************************************************************
+check for existance of a dir
+****************************************************************************/
+static BOOL chkpath(char *path,BOOL report)
+{
+ fstring path2;
+ pstring inbuf,outbuf;
+ char *p;
+
+ fstrcpy(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);
+ cli_setup_pkt(outbuf);
+
+ p = smb_buf(outbuf);
+ *p++ = 4;
+ fstrcpy(p,path2);
+
+#if 0
+ {
+ /* this little bit of code can be used to extract NT error codes.
+ Just feed a bunch of "cd foo" commands to smbclient then watch
+ in netmon (tridge) */
+ static int code=0;
+ SIVAL(outbuf, smb_rcls, code | 0xC0000000);
+ SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
+ code++;
+ }
+#endif
+
+ send_smb(Client,outbuf);
+ client_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);
+}
+
+static void
+daemonize(void)
+{
+ int i;
+ if ((i = fork()) < 0)
+ {
+ DEBUG(0, ("could not fork\n"));
+ }
+ if (i > 0)
+ {
+ /* parent simply exits */
+ exit(0);
+ }
+ setsid();
+ chdir("/");
+}
+
+static void
+close_our_files(void)
+{
+ int i;
+ for (i = 0; i < NR_OPEN; i++) {
+ if (i == Client) {
+ continue;
+ }
+ close(i);
+ }
+}
+
+static void
+usr1_handler(int x)
+{
+ return;
+}
+
+/*
+ * Send a login and store the connection options. This is a separate
+ * function to keep clientutil.c independent of linux kernel changes.
+ */
+static BOOL mount_send_login(char *inbuf, char *outbuf)
+{
+ struct connection_options opt;
+ int res = cli_send_login(inbuf, outbuf, True, True, &opt);
+
+ if (!res)
+ return res;
+
+ conn_options.protocol = opt.protocol;
+ conn_options.case_handling = CASE_LOWER;
+ conn_options.max_xmit = opt.max_xmit;
+ conn_options.server_uid = opt.server_uid;
+ conn_options.tid = opt.tid;
+ conn_options.secmode = opt.sec_mode;
+ conn_options.maxmux = opt.max_mux;
+ conn_options.maxvcs = opt.max_vcs;
+ conn_options.rawmode = opt.rawmode;
+ conn_options.sesskey = opt.sesskey;
+ conn_options.maxraw = opt.maxraw;
+ conn_options.capabilities = opt.capabilities;
+ conn_options.serverzone = opt.serverzone;
+
+ return True;
+}
+
+/*
+ * 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 *mount_point, char *inbuf, char *outbuf)
+{
+ int fd, closed = 0, res = 1;
+
+ while (1)
+ {
+ if ((fd = open(mount_point, O_RDONLY)) < 0)
+ {
+ DEBUG(0, ("smbmount: can't open %s\n", mount_point));
+ break;
+ }
+
+ /*
+ * Call the ioctl even if we couldn't get a socket ...
+ * there's no point in making smbfs wait for a timeout.
+ */
+ conn_options.fd = -1;
+ if (res)
+ conn_options.fd = Client;
+ res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
+ if (res != 0)
+ {
+ DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
+ }
+
+ close_sockets();
+ close(fd);
+ /*
+ * Close all open files if we haven't done so yet.
+ */
+#ifndef SMBFS_DEBUG
+ if (!closed)
+ {
+ closed = 1;
+ close_our_files();
+ }
+#endif
+
+ /*
+ * Wait for a signal from smbfs ...
+ */
+ CatchSignal(SIGUSR1, &usr1_handler);
+ pause();
+ DEBUG(0, ("smbmount: got signal, getting new socket\n"));
+
+ res = cli_open_sockets(port);
+ if (!res)
+ {
+ DEBUG(0, ("smbmount: can't open sockets\n"));
+ continue;
+ }
+
+ res = mount_send_login(inbuf, outbuf);
+ if (!res)
+ {
+ DEBUG(0, ("smbmount: login failed\n"));
+ }
+ }
+ DEBUG(0, ("smbmount: exit\n"));
+ exit(1);
+}
+
+/****************************************************************************
+mount smbfs
+****************************************************************************/
+static void cmd_mount(char *inbuf,char *outbuf)
+{
+ pstring mpoint;
+ pstring share_name;
+ pstring mount_command;
+ fstring buf;
+ int retval;
+ char mount_point[MAXPATHLEN+1];
+
+ if (!next_token(NULL, mpoint, NULL, sizeof(mpoint)))
+ {
+ DEBUG(0,("You must supply a mount point\n"));
+ return;
+ }
+
+ memset(mount_point, 0, sizeof(mount_point));
+
+ if (realpath(mpoint, mount_point) == NULL)
+ {
+ DEBUG(0, ("Could not resolve mount point\n"));
+ return;
+ }
+
+ /*
+ * Build the service name to report on the Unix side,
+ * converting '\' to '/' and ' ' to '_'.
+ */
+ pstrcpy(share_name, service);
+ string_replace(share_name, '\\', '/');
+ string_replace(share_name, ' ', '_');
+
+ slprintf(mount_command, sizeof(mount_command)-1,"smbmnt %s -s %s", mount_point, share_name);
+
+ while(next_token(NULL, buf, NULL, sizeof(buf)))
+ {
+ pstrcat(mount_command, " ");
+ pstrcat(mount_command, buf);
+ }
+
+ DEBUG(3, ("mount command: %s\n", mount_command));
+
+ /*
+ * Create the background process before trying the mount.
+ * (We delay closing files to allow diagnostic messages.)
+ */
+ daemonize();
+
+ /* The parent has exited here, the child handles the connection: */
+ if ((retval = system(mount_command)) != 0)
+ {
+ DEBUG(0,("mount failed\n"));
+ exit(1);
+ }
+ send_fs_socket(mount_point, inbuf, outbuf);
+}
+
+
+/* This defines the commands supported by this client */
+struct
+{
+ char *name;
+ void (*fn)();
+ char *description;
+} commands[] =
+{
+ {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
+ {"",NULL,NULL}
+};
+
+
+/*******************************************************************
+ lookup a command string in the list of commands, including
+ abbreviations
+ ******************************************************************/
+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))
+ {
+ matches++;
+ cmd = i;
+ }
+ i++;
+ }
+
+ if (matches == 0)
+ return(-1);
+ else if (matches == 1)
+ return(cmd);
+ else
+ return(-2);
+}
+
+/****************************************************************************
+help
+****************************************************************************/
+void cmd_help(char *dum_in, char *dum_out)
+{
+ int i=0,j;
+ fstring buf;
+
+ if (next_token(NULL,buf,NULL,sizeof(buf)))
+ {
+ 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++;
+ }
+ DEBUG(0,("\n"));
+ }
+}
+
+/****************************************************************************
+wait for keyboard activity, swallowing network packets
+****************************************************************************/
+static void wait_keyboard(char *buffer)
+{
+ fd_set fds;
+ int selrtn;
+ struct timeval timeout;
+
+ while (1)
+ {
+ extern int Client;
+ FD_ZERO(&fds);
+ FD_SET(Client,&fds);
+ FD_SET(fileno(stdin),&fds);
+
+ timeout.tv_sec = 20;
+ timeout.tv_usec = 0;
+ selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
+
+ if (FD_ISSET(fileno(stdin),&fds))
+ return;
+
+ /* 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(Client,&fds))
+ receive_smb(Client,buffer,0);
+
+ chkpath("\\",False);
+ }
+}
+
+
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
+static BOOL process(char *base_directory)
+{
+ extern FILE *dbf;
+ pstring line;
+ char *cmd;
+
+ char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+ char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+ if ((InBuffer == NULL) || (OutBuffer == NULL))
+ return(False);
+
+ bzero(OutBuffer,smb_size);
+
+ if (!mount_send_login(InBuffer,OutBuffer))
+ return(False);
+
+ cmd = cmdstr;
+ if (cmd[0] != '\0') while (cmd[0] != '\0')
+ {
+ char *p;
+ fstring tok;
+ int i;
+
+ if ((p = strchr(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;
+ }
+
+ /* input language code to internal one */
+ CNV_INPUT (line);
+
+ /* and get the first part of the command */
+ {
+ char *ptr = line;
+ if (!next_token(&ptr,tok,NULL,sizeof(tok))) 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)));
+ }
+ else while (!feof(stdin))
+ {
+ fstring tok;
+ int i;
+
+ bzero(OutBuffer,smb_size);
+
+ /* display a prompt */
+ DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
+ dbgflush();
+
+ wait_keyboard(InBuffer);
+
+ /* and get a response */
+ if (!fgets(line,1000,stdin))
+ break;
+
+ /* input language code to internal one */
+ CNV_INPUT (line);
+
+ /* 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,sizeof(tok))) 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)));
+ }
+
+ cli_send_logout(InBuffer,OutBuffer);
+ return(True);
+}
+
+/****************************************************************************
+usage on the program
+****************************************************************************/
+static void usage(char *pname)
+{
+ DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
+ pname));
+
+ DEBUG(0,("\nVersion %s\n",VERSION));
+ DEBUG(0,("\t-p port connect to 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-m max protocol set the max protocol level\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"));
+ DEBUG(0,("\t-c command string execute semicolon separated commands\n"));
+ DEBUG(0,("\t-t terminal code terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
+ DEBUG(0,("\t-D directory start from directory\n"));
+ DEBUG(0,("\n"));
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ fstring base_directory;
+ char *pname = argv[0];
+ int opt;
+ extern FILE *dbf;
+ extern char *optarg;
+ extern int optind;
+ pstring query_host;
+ BOOL nt_domain_logon = False;
+ static pstring servicesf = CONFIGFILE;
+ pstring term_code;
+ char *p;
+
+#ifdef KANJI
+ pstrcpy(term_code, KANJI);
+#else /* KANJI */
+ *term_code = 0;
+#endif /* KANJI */
+
+ *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"))
+ {
+ pstrcpy(username,getenv("USER"));
+
+ /* modification to support userid%passwd syntax in the USER var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if ((p=strchr(username,'%')))
+ {
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
+ }
+ strupper(username);
+ }
+
+ /* modification to support PASSWD environmental var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if (getenv("PASSWD"))
+ pstrcpy(password,getenv("PASSWD"));
+
+ if (*username == 0 && getenv("LOGNAME"))
+ {
+ pstrcpy(username,getenv("LOGNAME"));
+ strupper(username);
+ }
+
+ 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);
+ printf("\n%s: Not enough '\\' characters in service\n",service);
+ exit(1);
+ }
+
+ if (argc > 1 && (*argv[1] != '-'))
+ {
+ got_pass = True;
+ pstrcpy(password,argv[1]);
+ memset(argv[1],'X',strlen(argv[1]));
+ argc--;
+ argv++;
+ }
+ }
+
+ while ((opt =
+ getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
+ switch (opt)
+ {
+ case 'm':
+ max_protocol = interpret_protocol(optarg,max_protocol);
+ break;
+ case 'O':
+ pstrcpy(user_socket_options,optarg);
+ break;
+ case 'S':
+ pstrcpy(desthost,optarg);
+ strupper(desthost);
+ nt_domain_logon = True;
+ break;
+ case 'B':
+ iface_set_default(NULL,optarg,NULL);
+ break;
+ case 'D':
+ pstrcpy(base_directory,optarg);
+ break;
+ case 'i':
+ pstrcpy(scope,optarg);
+ break;
+ case 'U':
+ {
+ char *lp;
+ pstrcpy(username,optarg);
+ if ((lp=strchr(username,'%')))
+ {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr(optarg,'%')+1,'X',strlen(password));
+ }
+ }
+
+ break;
+ case 'W':
+ pstrcpy(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':
+ pstrcpy(global_myname,optarg);
+ break;
+ case 'N':
+ got_pass = True;
+ break;
+ case 'd':
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'l':
+ slprintf(debugf,sizeof(debugf)-1,"%s.client",optarg);
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'c':
+ cmdstr = optarg;
+ got_pass = True;
+ break;
+ case 'h':
+ usage(pname);
+ exit(0);
+ break;
+ case 's':
+ pstrcpy(servicesf, optarg);
+ break;
+ case 't':
+ pstrcpy(term_code, optarg);
+ break;
+ default:
+ usage(pname);
+ exit(1);
+ }
+
+ if (!*query_host && !*service)
+ {
+ usage(pname);
+ exit(1);
+ }
+
+
+ DEBUG( 3, ( "Client started (version %s)\n", VERSION ) );
+
+ if(!get_myname(myhostname,NULL))
+ {
+ DEBUG(0,("Failed to get my hostname.\n"));
+ }
+
+ if (!lp_load(servicesf,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ }
+
+ codepage_initialise(lp_client_code_page());
+
+ interpret_coding_system(term_code);
+
+ if (*workgroup == 0)
+ pstrcpy(workgroup,lp_workgroup());
+
+ load_interfaces();
+ get_myname((*global_myname)?NULL:global_myname,NULL);
+ strupper(global_myname);
+
+ if (cli_open_sockets(port))
+ {
+ if (!process(base_directory))
+ {
+ close_sockets();
+ return(1);
+ }
+ close_sockets();
+ }
+ else
+ return(1);
+
+ return(0);
+}
diff --git a/source/client/smbumount.c b/source/client/smbumount.c
new file mode 100644
index 00000000000..c3ba2620109
--- /dev/null
+++ b/source/client/smbumount.c
@@ -0,0 +1,175 @@
+/*
+ * 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>
+
+#include "includes.h"
+
+static char *progname;
+
+static void
+usage(void)
+{
+ printf("usage: %s mount-point\n", progname);
+}
+
+static int
+umount_ok(const char *mount_point)
+{
+ int fid = open(mount_point, O_RDONLY, 0);
+ 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. */
+char *
+canonicalize (const char *path)
+{
+ char *canonical = malloc (PATH_MAX + 1);
+
+ 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;
+
+ progname = argv[0];
+
+ if (argc != 2) {
+ usage();
+ exit(1);
+ }
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s must be installed suid root\n", progname);
+ 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/codepages/.cvsignore b/source/codepages/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/codepages/.cvsignore
diff --git a/source/codepages/codepage_def.437 b/source/codepages/codepage_def.437
new file mode 100644
index 00000000000..d357c074e44
--- /dev/null
+++ b/source/codepages/codepage_def.437
@@ -0,0 +1,70 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 437 - MS-DOS Latin US
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x87 0x80 True True
+ 0x81 0x9A True True
+ 0x82 0x90 True True
+ 0x83 0x41 True False
+ 0x84 0x8E True True
+ 0x85 0x41 True False
+ 0x86 0x8F True True
+ 0x88 0x45 True False
+ 0x89 0x45 True False
+ 0x8A 0x45 True False
+ 0x8B 0x49 True False
+ 0x8C 0x49 True False
+ 0x8D 0x49 True False
+ 0x91 0x92 True True
+ 0x93 0x4F True False
+ 0x94 0x99 True True
+ 0x95 0x4F True False
+ 0x96 0x55 True False
+ 0x97 0x55 True False
+ 0x9B 0 False False
+ 0x9C 0 False False
+ 0x9D 0 False False
+ 0xA0 0x41 True False
+ 0xA1 0x49 True False
+ 0xA2 0x4F True False
+ 0xA3 0x55 True False
+ 0xA4 0xA5 True True
+ 0xA8 0 False False
+ 0xAD 0 False False
+ 0xAE 0 False False
+ 0xAF 0 False False
+ 0xE0 0 False False
+ 0xE1 0 False False
+ 0xE2 0 False False
+ 0xE3 0 False False
+ 0xE4 0 False False
+ 0xE5 0 False False
+ 0xE6 0 False False
+ 0xE7 0 False False
+ 0xE8 0 False False
+ 0xE9 0 False False
+ 0xEA 0 False False
+ 0xEB 0 False False
+ 0xEC 0 False False
+ 0xED 0 False False
+ 0xEE 0 False False
+ 0xEF 0 False False
diff --git a/source/codepages/codepage_def.737 b/source/codepages/codepage_def.737
new file mode 100644
index 00000000000..9da99f3f3b0
--- /dev/null
+++ b/source/codepages/codepage_def.737
@@ -0,0 +1,58 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for Code Page 737 - Windows '95 Greek
+# defines lower->upper mapping.
+# Written by Manousaridis Haris <genesis@the.forthnet.gr>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x87 0x80 True True
+ 0x98 0x80 True True
+ 0x99 0x81 True True
+ 0x9A 0x82 True True
+ 0x9B 0x83 True True
+ 0x9C 0x84 True True
+ 0x9D 0x85 True True
+ 0x9E 0x86 True True
+ 0x9F 0x87 True True
+ 0xA0 0x88 True True
+ 0xA1 0x89 True True
+ 0xA2 0x8A True True
+ 0xA3 0x8B True True
+ 0xA4 0x8C True True
+ 0xA5 0x8D True True
+ 0xA6 0x8E True True
+ 0xA7 0x8F True True
+ 0xA8 0x90 True True
+ 0xA9 0x91 True True
+ 0xAA 0x91 True True
+ 0xAB 0x92 True True
+ 0xAC 0x93 True True
+ 0xAD 0x94 True True
+ 0xAE 0x95 True True
+ 0xAF 0x96 True True
+ 0xE0 0x97 True True
+ 0xE1 0xEA True True
+ 0xE2 0xEB True True
+ 0xE3 0xEC True True
+ 0xE4 0xF4 True True
+ 0xE5 0xED True True
+ 0xE6 0xEE True True
+ 0xE7 0xEF True True
+ 0xE8 0xF5 True True
+ 0xE9 0xF0 True True
diff --git a/source/codepages/codepage_def.850 b/source/codepages/codepage_def.850
new file mode 100644
index 00000000000..e2466a707af
--- /dev/null
+++ b/source/codepages/codepage_def.850
@@ -0,0 +1,54 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 850 - MS-DOS Latin 1
+# defines lower->upper mapping.
+# Written by Jeremy Allison (jallison@whistle.com)
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x85 0xB7 True True
+ 0xA0 0xB5 True True
+ 0x83 0xB6 True True
+ 0xC6 0xC7 True True
+ 0x84 0x8E True True
+ 0x86 0x8F True True
+ 0x91 0x92 True True
+ 0x87 0x80 True True
+ 0x8A 0xD4 True True
+ 0x82 0x90 True True
+ 0x88 0xD2 True True
+ 0x89 0xD3 True True
+ 0x8D 0xDE True True
+ 0xA1 0xD6 True True
+ 0x8C 0xD7 True True
+ 0x8B 0xD8 True True
+ 0xD0 0xD1 True True
+ 0xA4 0xA5 True True
+ 0x95 0xE3 True True
+ 0xA2 0xE0 True True
+ 0x93 0xE2 True True
+ 0xE4 0xE5 True True
+ 0x94 0x99 True True
+ 0x9B 0x9D True True
+ 0x97 0xEB True True
+ 0xA3 0xE9 True True
+ 0x96 0xEA True True
+ 0x81 0x9A True True
+ 0xEC 0xED True True
+ 0xE7 0xE8 True True
+ 0x9C 0 False False
diff --git a/source/codepages/codepage_def.852 b/source/codepages/codepage_def.852
new file mode 100644
index 00000000000..ed1423428ca
--- /dev/null
+++ b/source/codepages/codepage_def.852
@@ -0,0 +1,63 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 852 - MS-DOS Latin 2
+# defines lower->upper mapping.
+# Written by Leos Bitto <bitto@altec.cz>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x81 0x9A True True
+ 0x82 0x90 True True
+ 0x83 0xB6 True True
+ 0x84 0x8E True True
+ 0x85 0xDE True True
+ 0x86 0x8F True True
+ 0x87 0x80 True True
+ 0x88 0x9D True True
+ 0x89 0xD3 True True
+ 0x8B 0x8A True True
+ 0x8C 0xD7 True True
+ 0x92 0x91 True True
+ 0x93 0xE2 True True
+ 0x94 0x99 True True
+ 0x96 0x95 True True
+ 0x98 0x97 True True
+ 0x9C 0x9B True True
+ 0x9F 0xAC True True
+ 0xA0 0xB5 True True
+ 0xA1 0xD6 True True
+ 0xA2 0xE0 True True
+ 0xA3 0xE9 True True
+ 0xA5 0xA4 True True
+ 0xA7 0xA6 True True
+ 0xA9 0xA8 True True
+ 0xAB 0x8D True True
+ 0xAD 0xB8 True True
+ 0xBE 0xBD True True
+ 0xC7 0xC6 True True
+ 0xD0 0xD1 True True
+ 0xD4 0xD2 True True
+ 0xD8 0xB7 True True
+ 0xE4 0xE3 True True
+ 0xE5 0xD5 True True
+ 0xE7 0xE6 True True
+ 0xEA 0xE8 True True
+ 0xEC 0xED True True
+ 0xEE 0xDD True True
+ 0xFB 0xEB True True
+ 0xFD 0xFC True True
diff --git a/source/codepages/codepage_def.861 b/source/codepages/codepage_def.861
new file mode 100644
index 00000000000..b73fc576d85
--- /dev/null
+++ b/source/codepages/codepage_def.861
@@ -0,0 +1,135 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 861 - MS-DOS Icelandic
+# defines lower->upper mapping.
+# Written by Magn=FAs G=EDslason <magnus@hi.is>
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+ 0x85 0x41 True False # =E0
+ 0xA0 0xA4 True True # =E1 =C1
+ 0x83 0x41 True False # =E2
+ 0x84 0x8E True True # =E4 =C4
+ 0x86 0x8F True True # =E5 =C5
+ 0x91 0x92 True True # =E6 =C6
+ 0x87 0x80 True True # =E7 =C7
+ 0x8A 0x45 True False # =E8
+ 0x82 0x90 True True # =E9 =C9
+ 0x88 0x45 True False # =EA
+ 0x89 0x45 True False # =EB
+ 0xA1 0xA5 True True # =ED =CD
+ 0x8C 0x8B True True # =F0 =D0
+ 0xA2 0xA6 True True # =F3 =D3
+ 0x93 0x4F True False # =F4
+ 0x94 0x99 True True # =F6 =D6
+ 0x9B 0x9D True True # =F8 =D8
+ 0xA3 0xA7 True True # =FA =DA
+ 0x96 0x55 True False # =FB
+ 0x81 0x9A True True # =FC =DC
+ 0x98 0x97 True True # =FD =DD
+ 0x95 0x8D True True # =FE =DE
+ 0x9C 0 False False
+ 0x9E 0 False False
+ 0x9F 0 False False
+ 0xA8 0 False False
+ 0xA9 0 False False
+ 0xAA 0 False False
+ 0xAB 0 False False
+ 0xAC 0 False False
+ 0xAD 0 False False
+ 0xAE 0 False False
+ 0xAF 0 False False
+ 0xB0 0 False False
+ 0xB1 0 False False
+ 0xB2 0 False False
+ 0xB3 0 False False
+ 0xB4 0 False False
+ 0xB5 0 False False
+ 0xB6 0 False False
+ 0xB7 0 False False
+ 0xB8 0 False False
+ 0xB9 0 False False
+ 0xBA 0 False False
+ 0xBB 0 False False
+ 0xBC 0 False False
+ 0xBD 0 False False
+ 0xBE 0 False False
+ 0xBF 0 False False
+ 0xC0 0 False False
+ 0xC1 0 False False
+ 0xC2 0 False False
+ 0xC3 0 False False
+ 0xC4 0 False False
+ 0xC5 0 False False
+ 0xC6 0 False False
+ 0xC7 0 False False
+ 0xC8 0 False False
+ 0xC9 0 False False
+ 0xCA 0 False False
+ 0xCB 0 False False
+ 0xCC 0 False False
+ 0xCD 0 False False
+ 0xCE 0 False False
+ 0xCF 0 False False
+ 0xD0 0 False False
+ 0xD1 0 False False
+ 0xD2 0 False False
+ 0xD3 0 False False
+ 0xD4 0 False False
+ 0xD5 0 False False
+ 0xD6 0 False False
+ 0xD7 0 False False
+ 0xD8 0 False False
+ 0xD9 0 False False
+ 0xDA 0 False False
+ 0xDB 0 False False
+ 0xDC 0 False False
+ 0xDD 0 False False
+ 0xDE 0 False False
+ 0xDF 0 False False
+ 0xE0 0 False False
+ 0xE1 0 False False
+ 0xE2 0 False False
+ 0xE3 0 False False
+ 0xE4 0 False False
+ 0xE5 0 False False
+ 0xE6 0 False False
+ 0xE7 0 False False
+ 0xE8 0 False False
+ 0xE9 0 False False
+ 0xEA 0 False False
+ 0xEB 0 False False
+ 0xEC 0 False False
+ 0xED 0 False False
+ 0xEE 0 False False
+ 0xEF 0 False False
+ 0xF0 0 False False
+ 0xF1 0 False False
+ 0xF2 0 False False
+ 0xF3 0 False False
+ 0xF4 0 False False
+ 0xF5 0 False False
+ 0xF6 0 False False
+ 0xF7 0 False False
+ 0xF8 0 False False
+ 0xF9 0 False False
+ 0xFA 0 False False
+ 0xFB 0 False False
+ 0xFC 0 False False
+ 0xFD 0 False False
+ 0xFE 0 False False
+ 0xFF 0 False False
diff --git a/source/codepages/codepage_def.866 b/source/codepages/codepage_def.866
new file mode 100644
index 00000000000..c28d288be0b
--- /dev/null
+++ b/source/codepages/codepage_def.866
@@ -0,0 +1,168 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for Code Page 866 - MS-DOS Cyrillic
+# defines lower->upper mapping.
+# Written by ODiP ( odip@biogate.com )
+
+# The columns are :
+# lower upper map to lower map to upper
+#
+ 97 65 True True
+ 98 66 True True
+ 99 67 True True
+ 100 68 True True
+ 101 69 True True
+ 102 70 True True
+ 103 71 True True
+ 104 72 True True
+ 105 73 True True
+ 106 74 True True
+ 107 75 True True
+ 108 76 True True
+ 109 77 True True
+ 110 78 True True
+ 111 79 True True
+ 112 80 True True
+ 113 81 True True
+ 114 82 True True
+ 115 83 True True
+ 116 84 True True
+ 117 85 True True
+ 118 86 True True
+ 119 87 True True
+ 120 88 True True
+ 121 89 True True
+ 122 90 True True
+ 160 128 True True
+ 161 129 True True
+ 162 130 True True
+ 163 131 True True
+ 164 132 True True
+ 165 133 True True
+ 166 134 True True
+ 167 135 True True
+ 168 136 True True
+ 169 137 True True
+ 170 138 True True
+ 171 139 True True
+ 172 140 True True
+ 173 141 True True
+ 174 142 True True
+ 175 143 True True
+ 224 144 True True
+ 225 145 True True
+ 226 146 True True
+ 227 147 True True
+ 228 148 True True
+ 229 149 True True
+ 230 150 True True
+ 231 151 True True
+ 232 152 True True
+ 233 153 True True
+ 234 154 True True
+ 235 155 True True
+ 236 156 True True
+ 237 157 True True
+ 238 158 True True
+ 239 159 True True
+ 241 240 True True
+ 243 242 True True
+ 245 244 True True
+ 247 246 True True
+ 33 0 False False
+ 35 0 False False
+ 36 0 False False
+ 37 0 False False
+ 38 0 False False
+ 39 0 False False
+ 40 0 False False
+ 41 0 False False
+ 45 0 False False
+ 48 0 False False
+ 49 0 False False
+ 50 0 False False
+ 51 0 False False
+ 52 0 False False
+ 53 0 False False
+ 54 0 False False
+ 55 0 False False
+ 56 0 False False
+ 57 0 False False
+ 64 0 False False
+ 94 0 False False
+ 95 0 False False
+ 96 0 False False
+ 123 0 False False
+ 125 0 False False
+ 126 0 False False
+ 127 0 False False
+ 176 0 False False
+ 177 0 False False
+ 178 0 False False
+ 179 0 False False
+ 180 0 False False
+ 181 0 False False
+ 182 0 False False
+ 183 0 False False
+ 184 0 False False
+ 185 0 False False
+ 186 0 False False
+ 187 0 False False
+ 188 0 False False
+ 189 0 False False
+ 190 0 False False
+ 191 0 False False
+ 192 0 False False
+ 193 0 False False
+ 194 0 False False
+ 195 0 False False
+ 196 0 False False
+ 197 0 False False
+ 198 0 False False
+ 199 0 False False
+ 200 0 False False
+ 201 0 False False
+ 202 0 False False
+ 203 0 False False
+ 204 0 False False
+ 205 0 False False
+ 206 0 False False
+ 207 0 False False
+ 208 0 False False
+ 209 0 False False
+ 210 0 False False
+ 211 0 False False
+ 212 0 False False
+ 213 0 False False
+ 214 0 False False
+ 215 0 False False
+ 216 0 False False
+ 217 0 False False
+ 218 0 False False
+ 219 0 False False
+ 220 0 False False
+ 221 0 False False
+ 222 0 False False
+ 223 0 False False
+ 248 0 False False
+ 249 0 False False
+ 250 0 False False
+ 251 0 False False
+ 252 0 False False
+ 253 0 False False
+ 254 0 False False
+ 255 0 False False
diff --git a/source/codepages/codepage_def.932 b/source/codepages/codepage_def.932
new file mode 100644
index 00000000000..8d9ff631fba
--- /dev/null
+++ b/source/codepages/codepage_def.932
@@ -0,0 +1,24 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 932 - MS-DOS Japanese SJIS
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+# This file is intentionaly empty - no mappings are done. \ No newline at end of file
diff --git a/source/codepages/codepage_def.936 b/source/codepages/codepage_def.936
new file mode 100644
index 00000000000..25a317ffeaf
--- /dev/null
+++ b/source/codepages/codepage_def.936
@@ -0,0 +1,24 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 949 - MS-DOS Simplified Chinese.
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+# This file is intentionaly empty - no mappings are done.
diff --git a/source/codepages/codepage_def.949 b/source/codepages/codepage_def.949
new file mode 100644
index 00000000000..e3507904b58
--- /dev/null
+++ b/source/codepages/codepage_def.949
@@ -0,0 +1,24 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 949 - MS-DOS Korean Hangul
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+# This file is intentionaly empty - no mappings are done.
diff --git a/source/codepages/codepage_def.950 b/source/codepages/codepage_def.950
new file mode 100644
index 00000000000..8c6d56a5366
--- /dev/null
+++ b/source/codepages/codepage_def.950
@@ -0,0 +1,24 @@
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Codepage definition file for IBM Code Page 950 - MS-DOS Traditional Chinese
+# defines lower->upper mapping.
+# Written by Jeremy Allison <jallison@whistle.com>
+
+# The columns are :
+# lower upper map upper to lower map lower to upper
+#
+# This file is intentionaly empty - no mappings are done.
diff --git a/source/config.guess b/source/config.guess
new file mode 100755
index 00000000000..8ec56e286a8
--- /dev/null
+++ b/source/config.guess
@@ -0,0 +1,627 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc.
+#
+# 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.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# 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 system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+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
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ news*:NEWS-OS:6.*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ # 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.
+ echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'`
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-cbm-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ Pyramid*:OSx*:*:*)
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ sun4*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-unknown-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 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-atari-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-sun-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-apple-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:4*:UMIPS)
+ echo mips-mips-riscos4sysv
+ exit 0 ;;
+ mips:*:5*:RISCos)
+ echo mips-mips-riscos${UNAME_RELEASE}
+ 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 -o $UNAME_PROCESSOR = mc88110 ] ; then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${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[34]86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ 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-cc} dummy.c -o dummy && ./dummy && rm 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:*:4)
+ if /usr/sbin/lsattr -EHl proc0 | 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=4.${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 NetBSD 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/[3478]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;;
+ 9000/8?? ) HP_ARCH=hppa1.0 ;;
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ 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-cc} dummy.c -o dummy && ./dummy && rm 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 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ 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*T3E:*:*:*)
+ echo t3e-cray-unicos_mk
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*C90:*:*:*)
+ echo c90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp3[0-9][05]:OpenBSD:*:*)
+ echo m68k-hp-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i[34]86:BSD/386:*:* | *: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 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo i386-unknown-cygwin32
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin32
+ 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 ;;
+ *:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us.
+ ld_help_string=`ld --help 2>&1`
+ if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
+ echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
+ echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
+ echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then
+ echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then
+ echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
+ elif test "${UNAME_MACHINE}" = "alpha" ; then
+ echo alpha-unknown-linux ; exit 0
+ else
+ # Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
+ # useful --help. Gcc wants to distinguish between linuxoldld and linuxaout.
+ test ! -d /usr/lib/ldscripts/. \
+ && echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0
+ # Determine whether the default compiler is a.out or elf
+ cat >dummy.c <<EOF
+main(argc, argv)
+int argc;
+char *argv[];
+{
+#ifdef __ELF__
+ printf ("%s-unknown-linux\n", argv[1]);
+#else
+ printf ("%s-unknown-linuxaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ fi ;;
+# 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.
+ i[34]86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i[34]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}-unknown-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
+ echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv32
+ fi
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-unknown-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 ;;
+ M680[234]0:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3 && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m680[234]0:LynxOS:2.[23]*:*)
+ echo m68k-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i[34]86:LynxOS:2.[23]*:*)
+ echo i386-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.[23]*:*)
+ echo sparc-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.[23]*:*)
+ echo rs6000-lynx-lynxos${UNAME_RELEASE}
+ 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 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ R3000:*System_V*:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ 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
+
+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`;
+ printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3");
+ 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-unknown-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)
+ printf ("vax-dec-bsd\n"); exit (0);
+#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-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm 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
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/source/config.sub b/source/config.sub
new file mode 100755
index 00000000000..ccbdb0257d2
--- /dev/null
+++ b/source/config.sub
@@ -0,0 +1,1099 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+# 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.
+
+# 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
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+ echo Configuration name missing. 1>&2
+ echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ echo "or $0 ALIAS" 1>&2
+ echo where ALIAS is a recognized configuration type. 1>&2
+ exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### 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 )
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond ) # CYGNUS LOCAL
+ os=
+ basic_machine=$1
+ ;;
+ -apple*) # CYGNUS LOCAL
+ os=
+ basic_machine=$1
+ ;;
+ -scout) # CYGNUS LOCAL
+ ;;
+ -wrs) # CYGNUS LOCAL
+ os=vxworks
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+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.
+ tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | armeb \
+ | armel | pyramid \
+ | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+ | alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+ | powerpc | powerpcle | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+ | pdp11 | mips64el | mips64orion | mips64orionel \
+ | sparc | sparc8 | supersparc | microsparc | ultrasparc)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m88110 | m680[012346]0 | m683?2 | m68360 | z8k | v70 | h8500 | w65) # CYGNUS LOCAL
+ basic_machine=$basic_machine-unknown
+ ;;
+ mips64vr4300 | mips64vr4300el) # CYGNUS LOCAL jsmith
+ basic_machine=$basic_machine-unknown
+ ;;
+ # 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.
+ vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+ | sparc-* | ns32k-* | fx80-* | arm-* | arme[lb]-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
+ | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+ | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+ | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+ | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* \
+ | mips64-* | mipsel-* | mips64el-* | mips64orion-* \
+ | mips64orionel-* | sparc8-* | supersparc-* | microsparc-* | ultrasparc-*)
+ ;;
+ m88110-* | m680[012346]0-* | m683?2-* | m68360-* | z8k-* | h8500-*) # CYGNUS LOCAL
+ ;;
+ mips64vr4300-* | mips64vr4300el-*) # CYGNUS LOCAL jsmith
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd) # CYGNUS LOCAL
+ 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) # CYGNUS LOCAL
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k) # CYGNUS LOCAL
+ 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-cbm
+ ;;
+ amigados)
+ basic_machine=m68k-cbm
+ os=-amigados
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd) # CYGNUS LOCAL
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ arm | armel | armeb)
+ basic_machine=arm-arm
+ os=-aout
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ t3e-cray)
+ basic_machine=t3e-cray
+ os=-unicos_mk
+ ;;
+ 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
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ 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) # CYGNUS LOCAL
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray) # CYGNUS LOCAL
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms) # CYGNUS LOCAL
+ 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
+ ;;
+ w89k-*) # CYGNUS LOCAL
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ op50n-*) # CYGNUS LOCAL
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ op60c-*) # CYGNUS LOCAL
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ hppro) # CYGNUS LOCAL
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppaosf) # CYGNUS LOCAL
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[3456]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv32
+ ;;
+ i[3456]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv4
+ ;;
+ i[3456]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv
+ ;;
+ i[3456]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-solaris2
+ ;;
+ i386mach) # CYGNUS LOCAL
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta) # CYGNUS LOCAL
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ i386-go32 | go32) # CYGNUS LOCAL
+ basic_machine=i386-unknown
+ os=-go32
+ ;;
+ 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
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor) # CYGNUS LOCAL
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ msdos) # CYGNUS LOCAL
+ basic_machine=i386-unknown
+ os=-msdos
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown # CYGNUS LOCAL
+ os=-netbsd
+ ;;
+ 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) # CYGNUS LOCAL
+ 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
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ OSE68000 | ose68000) # CYGNUS LOCAL
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k) # CYGNUS LOCAL
+ 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)
+ basic_machine=i586-intel
+ ;;
+ pentiumpro | p6)
+ basic_machine=i686-intel
+ ;;
+ pentium-* | p5-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ k5)
+ # We don't have specific support for AMD's K5 yet, so just call it a Pentium
+ basic_machine=i586-amd
+ ;;
+ nexgen)
+ # We don't have specific support for Nexgen yet, so just call it a Pentium
+ basic_machine=i586-nexgen
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-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/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rom68k) # CYGNUS LOCAL
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sa29200) # CYGNUS LOCAL
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs) # CYGNUS LOCAL
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sparcfrw) # CYGNUS LOCAL
+ basic_machine=sparcfrw-sun
+ os=-sunos4
+ ;;
+ sparcfrwcompat) # CYGNUS LOCAL
+ basic_machine=sparcfrwcompat-sun
+ os=-sunos4
+ ;;
+ sparclitefrw) # CYGNUS LOCAL
+ basic_machine=sparclitefrw-fujitsu
+ ;;
+ sparclitefrwcompat) # CYGNUS LOCAL
+ basic_machine=sparclitefrwcompat-fujitsu
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000) # CYGNUS LOCAL
+ basic_machine=m68k-tandem
+ ;;
+ stratus) # CYGNUS LOCAL
+ 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
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810) # CYGNUS LOCAL
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k) # CYGNUS LOCAL
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*) # CYGNUS LOCAL
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ z8k-*-coff) # CYGNUS LOCAL
+ 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) # CYGNUS LOCAL
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n) # CYGNUS LOCAL
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c) # CYGNUS LOCAL
+ basic_machine=hppa1.1-oki
+ ;;
+ mips)
+ basic_machine=mips-mips
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw) # CYGNUS LOCAL
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw) # CYGNUS LOCAL
+ basic_machine=powerpc-apple
+ ;;
+ *)
+ 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
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -unixware* | svr4*)
+ os=-sysv4
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux|'`
+ ;;
+ # 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* | -lites* | -minix* | -genix* | -ultrix* | -irix* \
+ | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[3456]* \
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigados* | -msdos* | -moss* | -newsos* | -unicos* | -aos* \
+ | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+ | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -freebsd* | -openbsd* \
+ | -riscix* | -lites* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta | -udi \
+ | -eabi* | -ieee*)
+ ;;
+ # CYGNUS LOCAL
+ -go32 | -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -proelf | -os9* \
+ | -macos* | -mpw* | -magic* | -pe* | -win32)
+ ;;
+ -mac*) # CYGNUS LOCAL
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -386bsd) # CYGNUS LOCAL
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ # 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*) # CYGNUS LOCAL
+ os=-ose
+ ;;
+ -es1800*) # CYGNUS LOCAL
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -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
+ ;;
+ 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) # CYGNUS LOCAL
+ os=-aout
+ ;;
+ mips*-cisco) # CYGNUS LOCAL
+ os=-elf
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec) # CYGNUS LOCAL
+ os=-proelf
+ ;;
+ *-winbond) # CYGNUS LOCAL
+ os=-proelf
+ ;;
+ *-oki) # CYGNUS LOCAL
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigados
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-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
+ ;;
+ *-rom68k) # CYGNUS LOCAL
+ os=-coff
+ ;;
+ *-*bug) # CYGNUS LOCAL
+ os=-coff
+ ;;
+ *-apple) # CYGNUS LOCAL
+ os=-macos
+ ;;
+ *)
+ 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
+ ;;
+ -bosx*) # CYGNUS LOCAL
+ vendor=bull
+ ;;
+ -lynxos*)
+ vendor=lynx
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxworks*)
+ vendor=wrs
+ ;;
+ -hms*) # CYGNUS LOCAL
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*) # CYGNUS LOCAL
+ vendor=apple
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
diff --git a/source/configure b/source/configure
new file mode 100755
index 00000000000..e4b5faa6a14
--- /dev/null
+++ b/source/configure
@@ -0,0 +1,6046 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12
+# 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
+ --enable-maintainer-mode enable some make rules for maintainers"
+ac_help="$ac_help
+ --with-afs Include AFS support
+ --without-afs Don't include AFS support (default)"
+ac_help="$ac_help
+ --with-dfs Include DFS support
+ --without-dfs Don't include DFS support (default)"
+ac_help="$ac_help
+ --with-krb4=base-dir Include Kerberos IV support
+ --whithout-krb4 Don't include Kerbers IV support (default)"
+ac_help="$ac_help
+ --with-automount Include AUTOMOUNT support
+ --without-automount Don't include AUTOMOUNT support (default)"
+ac_help="$ac_help
+ --with-smbmount Include SMBMOUNT (Linux only) support
+ --without-smbmount Don't include SMBMOUNT support (default)"
+ac_help="$ac_help
+ --with-ldap Include LDAP support
+ --without-ldap Don't include LDAP support (default)"
+ac_help="$ac_help
+ --with-nisplus Include NISPLUS password database support
+ --without-nisplus Don't include NISPLUS password database support (default)"
+ac_help="$ac_help
+ --with-nisplus-home Include NISPLUS_HOME support
+ --without-nisplus-home Don't include NISPLUS_HOME support (default)"
+ac_help="$ac_help
+ --with-ssl Include SSL support
+ --without-ssl Don't include SSL support (default)"
+ac_help="$ac_help
+ --with-mmap Include experimental MMAP support
+ --without-mmap Don't include MMAP support (default)"
+ac_help="$ac_help
+ --with-syslog Include experimental SYSLOG support
+ --without-syslog Don't include SYSLOG support (default)"
+ac_help="$ac_help
+ --with-netatalk Include experimental Netatalk support
+ --without-netatalk Don't include experimental Netatalk support (default)"
+
+# 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=
+# 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.12"
+ 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 $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+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
+
+
+
+
+# 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:565: 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="${IFS}:"
+ for ac_dir in $PATH; 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:594: 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="${IFS}:"
+ ac_prog_rejected=no
+ for ac_dir in $PATH; 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
+
+ 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:642: 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 $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 652 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:656: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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*
+
+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:676: 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:681: 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:690: \"$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
+ 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:705: 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
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-O2"
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+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
+# 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:762: 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="${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.
+ for ac_prog in ginstall installbsd 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.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ 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_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:818: 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="${IFS}:"
+ for ac_dir in $PATH; 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
+
+
+
+# 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 $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:875: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`$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=`$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:896: 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=`$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:914: 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=`$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
+ *linux*) cat >> confdefs.h <<\EOF
+#define LINUX 1
+EOF
+;;
+ *solaris*) cat >> confdefs.h <<\EOF
+#define SUNOS5 1
+EOF
+;;
+ *sunos*) cat >> confdefs.h <<\EOF
+#define SUNOS4 1
+EOF
+;;
+ *irix*) cat >> confdefs.h <<\EOF
+#define IRIX 1
+EOF
+;;
+ *aix*) cat >> confdefs.h <<\EOF
+#define AIX 1
+EOF
+;;
+ *hpux*) cat >> confdefs.h <<\EOF
+#define HPUX 1
+EOF
+;;
+ *qnx*) cat >> confdefs.h <<\EOF
+#define QNX 1
+EOF
+;;
+ *osf1*) cat >> confdefs.h <<\EOF
+#define OSF1 1
+EOF
+;;
+ *sco*) cat >> confdefs.h <<\EOF
+#define SCO 1
+EOF
+;;
+ *next2*) cat >> confdefs.h <<\EOF
+#define NEXT2 1
+EOF
+;;
+esac
+
+
+
+ echo $ac_n "checking config.cache system type""... $ac_c" 1>&6
+echo "configure:982: 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"
+
+
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ maint_mode=$enableval
+else
+ maint_mode=no
+fi
+
+ if test x"$maint_mode" = x"yes"; then MAINT=; else MAINT='#'; fi
+
+ # Extract the first word of "autoconf", so it can be a program name with args.
+set dummy autoconf; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1012: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_AUTOCONF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$AUTOCONF" in
+ /*)
+ ac_cv_path_AUTOCONF="$AUTOCONF" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_AUTOCONF="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_AUTOCONF" && ac_cv_path_AUTOCONF="autoconf"
+ ;;
+esac
+fi
+AUTOCONF="$ac_cv_path_AUTOCONF"
+if test -n "$AUTOCONF"; then
+ echo "$ac_t""$AUTOCONF" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+ # Extract the first word of "autoheader", so it can be a program name with args.
+set dummy autoheader; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1045: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_AUTOHEADER'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$AUTOHEADER" in
+ /*)
+ ac_cv_path_AUTOHEADER="$AUTOHEADER" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_AUTOHEADER="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_AUTOHEADER" && ac_cv_path_AUTOHEADER="autoheader"
+ ;;
+esac
+fi
+AUTOHEADER="$ac_cv_path_AUTOHEADER"
+if test -n "$AUTOHEADER"; then
+ echo "$ac_t""$AUTOHEADER" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:1078: 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 1085 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:1092: \"$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:1118: 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 1133 "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:1139: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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 1150 "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:1156: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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*
+ 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:1179: 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 1184 "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:1192: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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 1209 "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 1227 "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 1248 "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:1259: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:1287: 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 1292 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1300: \"$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:1325: 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 1333 "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:1344: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:1366: 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 1374 "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:1385: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:1408: 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 1413 "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:1422: \"$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:1443: 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 1448 "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:1464: \"$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 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:1488: 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 1493 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1498: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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:1528: 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 1533 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1538: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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/types.h rpc/xdr.h rpc/auth.h rpc/clnt.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1568: 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 1573 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1578: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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 rpcsvc/yp_prot.h rpcsvc/ypclnt.h sys/param.h ctype.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1608: 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 1613 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1618: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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/wait.h sys/resource.h sys/ioctl.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:1648: 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 1653 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1658: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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/filio.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:1688: 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 1693 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1698: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1728: 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 1733 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1738: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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/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:1768: 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 1773 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1778: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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 shadow.h netinet/tcp.h sys/security.h security/pam_appl.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1808: 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 1813 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1818: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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 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:1848: 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 1853 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1858: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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 sys/capability.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1888: 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 1893 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1898: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+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:1926: 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 1934 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(int));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1945: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:1965: 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 1973 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(long));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1984: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:2004: 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 2012 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(short));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2023: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:2044: 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 2049 "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:2098: \"$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:2119: 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 2126 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:2133: \"$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:2159: 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 2166 "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:2177: \"$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 2181 "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:2192: \"$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 2212 "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:2225: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:2249: 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 2256 "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 2278 "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:2288: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:2313: 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 2318 "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:2335: \"$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:2354: 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 2359 "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:2388: 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 2393 "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 "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:2421: 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 2426 "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 "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:2454: 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 2459 "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 "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:2487: 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 2492 "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 "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:2520: 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 2525 "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:2533: \"$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 ino_t""... $ac_c" 1>&6
+echo "configure:2554: 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 2559 "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 "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 ssize_t""... $ac_c" 1>&6
+echo "configure:2587: 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 2592 "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 "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 errno in errno.h""... $ac_c" 1>&6
+echo "configure:2621: checking for errno in errno.h" >&5
+if eval "test \"`echo '$''{'samba_cv_errno'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2627 "configure"
+#include "confdefs.h"
+#include <errno.h>
+int main() {
+int i = errno
+; return 0; }
+EOF
+if { (eval echo configure:2634: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_errno=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_have_errno_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_errno" 1>&6
+if test x"$samba_cv_errno" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ERRNO_DECL 1
+EOF
+
+fi
+
+# stupid glibc has the functions but no declaration. grrrr.
+echo $ac_n "checking for setresuid declaration""... $ac_c" 1>&6
+echo "configure:2656: checking for setresuid declaration" >&5
+if eval "test \"`echo '$''{'samba_cv_have_setresuid_decl'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2662 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+int main() {
+int i = setresuid
+; return 0; }
+EOF
+if { (eval echo configure:2669: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_have_setresuid_decl=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_have_setresuid_decl=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_have_setresuid_decl" 1>&6
+if test x"$samba_cv_have_setresuid_decl" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SETRESUID_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:2692: 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 2701 "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:2706: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:2729: 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 2737 "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:2747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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.o"
+
+
+###############################################
+# 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:2770: 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 2775 "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:2798: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:2824: 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 2832 "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:2843: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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
+
+
+###############################################
+# test for where we get pam_authenticate() from
+# might need libdl for this to work
+if test "$ac_cv_header_security_pam_appl_h" = "yes"; then
+ echo $ac_n "checking for main in -ldl""... $ac_c" 1>&6
+echo "configure:2875: checking for main in -ldl" >&5
+ac_lib_var=`echo dl'_'main | 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 2883 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2890: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ldl $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+for ac_func in pam_authenticate
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2921: 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 2926 "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:2949: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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_pam_authenticate" = x"no"; then
+ echo $ac_n "checking for pam_authenticate in -lpam""... $ac_c" 1>&6
+echo "configure:2975: checking for pam_authenticate in -lpam" >&5
+ac_lib_var=`echo pam'_'pam_authenticate | 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 2983 "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_authenticate();
+
+int main() {
+pam_authenticate()
+; return 0; }
+EOF
+if { (eval echo configure:2994: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 -lpam"
+ cat >> confdefs.h <<\EOF
+#define HAVE_PAM_AUTHENTICATE 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+###############################################
+# test for where we get readline() from
+if test "$ac_cv_header_readline_h" = "yes" ||
+ test "$ac_cv_header_readline_readline_h" = "yes"; then
+ echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
+echo "configure:3026: checking for readline in -lreadline" >&5
+ac_lib_var=`echo readline'_'readline | 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 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3034 "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 readline();
+
+int main() {
+readline()
+; return 0; }
+EOF
+if { (eval echo configure:3045: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 readline | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lreadline $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+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:3084: 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 3089 "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:3112: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:3140: 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 3148 "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:3159: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:3190: 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 3198 "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:3209: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:3240: 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 3248 "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:3259: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:3290: 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 3298 "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:3309: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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
+
+
+for ac_func in waitpid getcwd strdup strerror chown chmod chroot
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3352: 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 3357 "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:3380: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 execl bzero memset
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3407: 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 3412 "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:3435: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 setsid glob strpbrk pipe crypt16 getauthuid
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3462: 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 3467 "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:3490: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 innetgr
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3517: 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 3522 "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:3545: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 rdchk getgrnam pathconf putprpwnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3572: 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 3577 "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:3600: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 setuidx setgroups mktime rename ftruncate stat64 fstat64 lstat64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3627: 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 3632 "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:3655: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 set_auth_parameters atexit grantpt getspnam dup2 lseek64 ftruncate64
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3682: 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 3687 "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:3710: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 ftell64 bigcrypt getprpwnam setluid yp_get_default_domain getpwanam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3737: 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 3742 "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:3765: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3792: 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 3797 "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:3820: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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 long long""... $ac_c" 1>&6
+echo "configure:3846: 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 3855 "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:3860: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+echo $ac_n "checking for 64 bit off_t""... $ac_c" 1>&6
+echo "configure:3883: 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 3892 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(off_t) == 8) ? 0 : 1); }
+EOF
+if { (eval echo configure:3898: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:3921: 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 3930 "configure"
+#include "confdefs.h"
+#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:3936: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:3959: 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 3968 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+#include <sys/stat.h>
+main() { exit((sizeof(ino_t) == 8) ? 0 : 1); }
+EOF
+if { (eval echo configure:3974: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:3997: 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 4006 "configure"
+#include "confdefs.h"
+#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:4012: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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 union semun""... $ac_c" 1>&6
+echo "configure:4035: checking for union semun" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_UNION_SEMUN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_UNION_SEMUN=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4044 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+main() { union semun ss; exit(0); }
+EOF
+if { (eval echo configure:4052: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_UNION_SEMUN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_UNION_SEMUN=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_UNION_SEMUN" 1>&6
+if test x"$samba_cv_HAVE_UNION_SEMUN" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UNION_SEMUN 1
+EOF
+
+fi
+
+echo $ac_n "checking for unsigned char""... $ac_c" 1>&6
+echo "configure:4075: 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 4084 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main() { char c; c=250; exit((c > 0)?0:1); }
+EOF
+if { (eval echo configure:4089: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:4112: 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 4118 "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:4127: \"$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 for __FILE__ macro""... $ac_c" 1>&6
+echo "configure:4148: 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 4154 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+printf("%s\n", __FILE__);
+; return 0; }
+EOF
+if { (eval echo configure:4161: \"$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:4182: 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 4188 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() {
+printf("%s\n", __FUNCTION__);
+; return 0; }
+EOF
+if { (eval echo configure:4195: \"$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:4216: 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 4225 "configure"
+#include "confdefs.h"
+
+#include <sys/time.h>
+#include <unistd.h>
+main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}
+EOF
+if { (eval echo configure:4232: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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 broken readdir""... $ac_c" 1>&6
+echo "configure:4256: 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 4265 "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:4273: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:4296: 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 4302 "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:4310: \"$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
+
+echo $ac_n "checking for kernel oplock type definitions""... $ac_c" 1>&6
+echo "configure:4331: checking for kernel oplock type definitions" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_KERNEL_OPLOCKS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+cat > conftest.$ac_ext <<EOF
+#line 4337 "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:4345: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ samba_cv_HAVE_KERNEL_OPLOCKS=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ samba_cv_HAVE_KERNEL_OPLOCKS=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$samba_cv_HAVE_KERNEL_OPLOCKS" 1>&6
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_KERNEL_OPLOCKS 1
+EOF
+
+fi
+
+echo $ac_n "checking for irix specific capabilities""... $ac_c" 1>&6
+echo "configure:4366: 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 4375 "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:4390: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+echo $ac_n "checking for test routines""... $ac_c" 1>&6
+echo "configure:4413: 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 4418 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/trivial.c"
+EOF
+if { (eval echo configure:4422: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:4436: 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 4445 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/ftruncate.c"
+EOF
+if { (eval echo configure:4449: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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 broken getgroups""... $ac_c" 1>&6
+echo "configure:4472: 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 4481 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/getgroups.c"
+EOF
+if { (eval echo configure:4485: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:4508: 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-.}/include -I${srcdir-.}/ubiqx"
+cat > conftest.$ac_ext <<EOF
+#line 4516 "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:4529: \"$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:4552: 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 4561 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+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:4573: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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 root""... $ac_c" 1>&6
+echo "configure:4596: 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 4605 "configure"
+#include "confdefs.h"
+main() { exit(getuid() != 0); }
+EOF
+if { (eval echo configure:4609: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+netmask=no;
+echo $ac_n "checking for netmask ifconf""... $ac_c" 1>&6
+echo "configure:4635: checking for netmask ifconf" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_NETMASK_IFCONF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_NETMASK_IFCONF=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4644 "configure"
+#include "confdefs.h"
+
+#define HAVE_NETMASK_IFCONF 1
+#define AUTOCONF 1
+#include "${srcdir-.}/lib/netmask.c"
+EOF
+if { (eval echo configure:4651: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_NETMASK_IFCONF=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_NETMASK_IFCONF=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_NETMASK_IFCONF" 1>&6
+if test x"$samba_cv_HAVE_NETMASK_IFCONF" = x"yes"; then
+ netmask=yes;cat >> confdefs.h <<\EOF
+#define HAVE_NETMASK_IFCONF 1
+EOF
+
+fi
+
+if test $netmask = no; then
+echo $ac_n "checking for netmask ifreq""... $ac_c" 1>&6
+echo "configure:4675: checking for netmask ifreq" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_NETMASK_IFREQ'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_NETMASK_IFREQ=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4684 "configure"
+#include "confdefs.h"
+
+#define HAVE_NETMASK_IFREQ 1
+#define AUTOCONF 1
+#include "${srcdir-.}/lib/netmask.c"
+EOF
+if { (eval echo configure:4691: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_NETMASK_IFREQ=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_NETMASK_IFREQ=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_NETMASK_IFREQ" 1>&6
+if test x"$samba_cv_HAVE_NETMASK_IFREQ" = x"yes"; then
+ netmask=yes;cat >> confdefs.h <<\EOF
+#define HAVE_NETMASK_IFREQ 1
+EOF
+
+fi
+fi
+
+if test $netmask = no; then
+echo $ac_n "checking for netmask AIX""... $ac_c" 1>&6
+echo "configure:4716: checking for netmask AIX" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_NETMASK_AIX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_NETMASK_AIX=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4725 "configure"
+#include "confdefs.h"
+
+#define HAVE_NETMASK_AIX 1
+#define AUTOCONF 1
+#include "${srcdir-.}/lib/netmask.c"
+EOF
+if { (eval echo configure:4732: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_NETMASK_AIX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_NETMASK_AIX=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_NETMASK_AIX" 1>&6
+if test x"$samba_cv_HAVE_NETMASK_AIX" = x"yes"; then
+ netmask=yes;cat >> confdefs.h <<\EOF
+#define HAVE_NETMASK_AIX 1
+EOF
+
+fi
+fi
+
+echo $ac_n "checking for trapdoor seteuid""... $ac_c" 1>&6
+echo "configure:4756: checking for trapdoor seteuid" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_TRAPDOOR_UID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4765 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/trapdoor.c"
+EOF
+if { (eval echo configure:4769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_TRAPDOOR_UID=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_TRAPDOOR_UID=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_TRAPDOOR_UID" 1>&6
+if test x"$samba_cv_HAVE_TRAPDOOR_UID" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_TRAPDOOR_UID 1
+EOF
+
+fi
+
+echo $ac_n "checking for shared mmap""... $ac_c" 1>&6
+echo "configure:4792: checking for shared mmap" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_SHARED_MMAP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_SHARED_MMAP=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4801 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/shared_mmap.c"
+EOF
+if { (eval echo configure:4805: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_SHARED_MMAP=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_SHARED_MMAP=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_SHARED_MMAP" 1>&6
+if test x"$samba_cv_HAVE_SHARED_MMAP" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SHARED_MMAP 1
+EOF
+
+fi
+
+echo $ac_n "checking for fcntl locking""... $ac_c" 1>&6
+echo "configure:4828: 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 4837 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/fcntl_lock.c"
+EOF
+if { (eval echo configure:4841: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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 64 bit fcntl locking""... $ac_c" 1>&6
+echo "configure:4864: 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 4873 "configure"
+#include "confdefs.h"
+
+#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:4894: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+echo $ac_n "checking for sysv ipc""... $ac_c" 1>&6
+echo "configure:4917: checking for sysv ipc" >&5
+if eval "test \"`echo '$''{'samba_cv_HAVE_SYSV_IPC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+if test "$cross_compiling" = yes; then
+ samba_cv_HAVE_SYSV_IPC=cross
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4926 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/sysv_ipc.c"
+EOF
+if { (eval echo configure:4930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ samba_cv_HAVE_SYSV_IPC=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ samba_cv_HAVE_SYSV_IPC=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$samba_cv_HAVE_SYSV_IPC" 1>&6
+if test x"$samba_cv_HAVE_SYSV_IPC" = x"yes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYSV_IPC 1
+EOF
+
+fi
+
+#################################################
+# check for the AFS filesystem
+echo $ac_n "checking whether to use AFS""... $ac_c" 1>&6
+echo "configure:4955: checking whether to use AFS" >&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 auth system
+echo $ac_n "checking whether to use DFS auth""... $ac_c" 1>&6
+echo "configure:4981: checking whether to use DFS 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
+
+
+#################################################
+# check for Kerberos IV auth system
+echo $ac_n "checking whether to use Kerberos IV""... $ac_c" 1>&6
+echo "configure:5006: checking whether to use Kerberos IV" >&5
+# Check whether --with-krb4 or --without-krb4 was given.
+if test "${with_krb4+set}" = set; then
+ withval="$with_krb4"
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define KRB4_AUTH 1
+EOF
+
+ echo $ac_n "checking for dn_expand in -lresolv""... $ac_c" 1>&6
+echo "configure:5016: 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 5024 "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:5035: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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
+
+ LIBS="$LIBS -lkrb -ldes"
+ CFLAGS="$CFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for automount support
+echo $ac_n "checking whether to use AUTOMOUNT""... $ac_c" 1>&6
+echo "configure:5074: 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:5099: 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)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_SMBMOUNT 1
+EOF
+
+ MPROGS="bin/smbmount bin/smbmnt bin/smbumount"
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ MPROGS=
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+ MPROGS=
+
+fi
+
+
+#################################################
+# check for a LDAP password database
+echo $ac_n "checking whether to use LDAP password database""... $ac_c" 1>&6
+echo "configure:5127: checking whether to use LDAP password database" >&5
+# Check whether --with-ldap or --without-ldap was given.
+if test "${with_ldap+set}" = set; then
+ withval="$with_ldap"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_LDAP 1
+EOF
+
+ ;;
+ *)
+ 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 password database""... $ac_c" 1>&6
+echo "configure:5152: checking whether to use NISPLUS password database" >&5
+# Check whether --with-nisplus or --without-nisplus was given.
+if test "${with_nisplus+set}" = set; then
+ withval="$with_nisplus"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_NISPLUS 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for a NISPLUS_HOME support
+echo $ac_n "checking whether to use NISPLUS_HOME""... $ac_c" 1>&6
+echo "configure:5177: 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:5202: 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
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+#################################################
+# check for experimental mmap support
+echo $ac_n "checking whether to use MMAP""... $ac_c" 1>&6
+echo "configure:5227: checking whether to use MMAP" >&5
+# Check whether --with-mmap or --without-mmap was given.
+if test "${with_mmap+set}" = set; then
+ withval="$with_mmap"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_MMAP 1
+EOF
+
+ ;;
+ *)
+ 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:5252: 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 experimental netatalk resource fork support
+echo $ac_n "checking whether to support netatalk""... $ac_c" 1>&6
+echo "configure:5277: checking whether to support netatalk" >&5
+# Check whether --with-netatalk or --without-netatalk was given.
+if test "${with_netatalk+set}" = set; then
+ withval="$with_netatalk"
+ case "$withval" in
+ yes)
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define WITH_NETATALK 1
+EOF
+
+ ;;
+ *)
+ echo "$ac_t""no" 1>&6
+ ;;
+ esac
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+
+#################################################
+# these tests are taken from the GNU fileutils package
+echo "checking how to get filesystem space usage" 1>&6
+echo "configure:5303: 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:5310: 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 5318 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ main ()
+ {
+ struct statvfs64 fsd;
+ exit (statfs64 (".", &fsd));
+ }
+EOF
+if { (eval echo configure:5329: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:5362: 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 5367 "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:5375: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; 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:5400: 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 5408 "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:5421: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:5448: 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 5456 "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:5475: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:5502: 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 5510 "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:5520: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:5547: 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 5555 "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:5571: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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:5598: 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 5606 "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:5626: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+echo "checking configure summary"
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5655 "configure"
+#include "confdefs.h"
+#include "${srcdir-.}/tests/summary.c"
+EOF
+if { (eval echo configure:5659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./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
+
+
+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) 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.12"
+ 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%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%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%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@SHELL@%$SHELL%g
+s%@MPROGS@%$MPROGS%g
+s%@AWK@%$AWK%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%@MAINT@%$MAINT%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%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.in b/source/configure.in
new file mode 100644
index 00000000000..30eb5d14d9e
--- /dev/null
+++ b/source/configure.in
@@ -0,0 +1,863 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(include/includes.h)
+AC_CONFIG_HEADER(include/config.h)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_SUBST(SHELL)
+AC_SUBST(MPROGS)
+AC_PROG_AWK
+
+AC_CANONICAL_SYSTEM
+case "$host_os" in
+ *linux*) AC_DEFINE(LINUX);;
+ *solaris*) AC_DEFINE(SUNOS5);;
+ *sunos*) AC_DEFINE(SUNOS4);;
+ *irix*) AC_DEFINE(IRIX);;
+ *aix*) AC_DEFINE(AIX);;
+ *hpux*) AC_DEFINE(HPUX);;
+ *qnx*) AC_DEFINE(QNX);;
+ *osf1*) AC_DEFINE(OSF1);;
+ *sco*) AC_DEFINE(SCO);;
+ *next2*) AC_DEFINE(NEXT2);;
+esac
+
+AC_VALIDATE_CACHE_SYSTEM_TYPE
+SAMBA_MAINTAINER_MODE
+
+AC_INLINE
+AC_HEADER_STDC
+AC_HEADER_DIRENT
+AC_HEADER_TIME
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(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/types.h rpc/xdr.h rpc/auth.h rpc/clnt.h)
+AC_CHECK_HEADERS(rpcsvc/yp_prot.h rpcsvc/ypclnt.h sys/param.h ctype.h )
+AC_CHECK_HEADERS(sys/wait.h sys/resource.h sys/ioctl.h sys/mode.h)
+AC_CHECK_HEADERS(sys/filio.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)
+AC_CHECK_HEADERS(sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h)
+AC_CHECK_HEADERS(shadow.h netinet/tcp.h sys/security.h security/pam_appl.h)
+AC_CHECK_HEADERS(stropts.h poll.h readline.h history.h readline/readline.h)
+AC_CHECK_HEADERS(readline/history.h sys/capability.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_CHECK_TYPE(ino_t,unsigned)
+AC_CHECK_TYPE(ssize_t, int)
+
+AC_CACHE_CHECK([for errno in errno.h],samba_cv_errno, [
+ AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
+ samba_cv_errno=yes,samba_cv_have_errno_decl=no)])
+if test x"$samba_cv_errno" = x"yes"; then
+ AC_DEFINE(HAVE_ERRNO_DECL)
+fi
+
+# stupid glibc has the functions but no declaration. grrrr.
+AC_CACHE_CHECK([for setresuid declaration],samba_cv_have_setresuid_decl,[
+ AC_TRY_COMPILE([#include <unistd.h>],[int i = setresuid],
+ samba_cv_have_setresuid_decl=yes,samba_cv_have_setresuid_decl=no)])
+if test x"$samba_cv_have_setresuid_decl" = x"yes"; then
+ AC_DEFINE(HAVE_SETRESUID_DECL)
+fi
+
+# 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
+
+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
+
+
+###############################################
+# test for where we get pam_authenticate() from
+# might need libdl for this to work
+if test "$ac_cv_header_security_pam_appl_h" = "yes"; then
+ AC_CHECK_LIB(dl,main)
+fi
+AC_CHECK_FUNCS(pam_authenticate)
+if test x"$ac_cv_func_pam_authenticate" = x"no"; then
+ AC_CHECK_LIB(pam, pam_authenticate, [LIBS="$LIBS -lpam"
+ AC_DEFINE(HAVE_PAM_AUTHENTICATE)])
+fi
+
+
+###############################################
+# test for where we get readline() from
+if test "$ac_cv_header_readline_h" = "yes" ||
+ test "$ac_cv_header_readline_readline_h" = "yes"; then
+ AC_CHECK_LIB(readline,readline)
+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.
+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
+
+
+AC_CHECK_FUNCS(waitpid getcwd strdup strerror chown chmod chroot)
+AC_CHECK_FUNCS(fstat strchr utime utimes getrlimit fsync execl bzero memset)
+AC_CHECK_FUNCS(memmove vsnprintf setsid glob strpbrk pipe crypt16 getauthuid)
+AC_CHECK_FUNCS(strftime sigprocmask sigblock sigaction innetgr)
+AC_CHECK_FUNCS(initgroups select rdchk getgrnam pathconf putprpwnam)
+AC_CHECK_FUNCS(setuidx setgroups mktime rename ftruncate stat64 fstat64 lstat64)
+AC_CHECK_FUNCS(set_auth_parameters atexit grantpt getspnam dup2 lseek64 ftruncate64)
+AC_CHECK_FUNCS(fseek64 ftell64 bigcrypt getprpwnam setluid yp_get_default_domain getpwanam)
+AC_CHECK_FUNCS(srandom random srand rand)
+
+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
+
+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([#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([#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 union semun],samba_cv_HAVE_UNION_SEMUN,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+main() { union semun ss; exit(0); }],
+samba_cv_HAVE_UNION_SEMUN=yes,samba_cv_HAVE_UNION_SEMUN=no,samba_cv_HAVE_UNION_SEMUN=cross)])
+if test x"$samba_cv_HAVE_UNION_SEMUN" = x"yes"; then
+ AC_DEFINE(HAVE_UNION_SEMUN)
+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([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 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
+
+AC_CACHE_CHECK([for kernel oplock type definitions],samba_cv_HAVE_KERNEL_OPLOCKS,[
+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=yes,samba_cv_HAVE_KERNEL_OPLOCKS=no)])
+if test x"$samba_cv_HAVE_KERNEL_OPLOCKS" = x"yes"; then
+ AC_DEFINE(HAVE_KERNEL_OPLOCKS)
+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
+
+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 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-.}/include -I${srcdir-.}/ubiqx"
+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>
+#include <arpa/inet.h>
+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 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
+
+netmask=no;
+AC_CACHE_CHECK([for netmask ifconf],samba_cv_HAVE_NETMASK_IFCONF,[
+AC_TRY_RUN([
+#define HAVE_NETMASK_IFCONF 1
+#define AUTOCONF 1
+#include "${srcdir-.}/lib/netmask.c"],
+ samba_cv_HAVE_NETMASK_IFCONF=yes,samba_cv_HAVE_NETMASK_IFCONF=no,samba_cv_HAVE_NETMASK_IFCONF=cross)])
+if test x"$samba_cv_HAVE_NETMASK_IFCONF" = x"yes"; then
+ netmask=yes;AC_DEFINE(HAVE_NETMASK_IFCONF)
+fi
+
+if test $netmask = no; then
+AC_CACHE_CHECK([for netmask ifreq],samba_cv_HAVE_NETMASK_IFREQ,[
+AC_TRY_RUN([
+#define HAVE_NETMASK_IFREQ 1
+#define AUTOCONF 1
+#include "${srcdir-.}/lib/netmask.c"],
+ samba_cv_HAVE_NETMASK_IFREQ=yes,samba_cv_HAVE_NETMASK_IFREQ=no,samba_cv_HAVE_NETMASK_IFREQ=cross)])
+if test x"$samba_cv_HAVE_NETMASK_IFREQ" = x"yes"; then
+ netmask=yes;AC_DEFINE(HAVE_NETMASK_IFREQ)
+fi
+fi
+
+if test $netmask = no; then
+AC_CACHE_CHECK([for netmask AIX],samba_cv_HAVE_NETMASK_AIX,[
+AC_TRY_RUN([
+#define HAVE_NETMASK_AIX 1
+#define AUTOCONF 1
+#include "${srcdir-.}/lib/netmask.c"],
+ samba_cv_HAVE_NETMASK_AIX=yes,samba_cv_HAVE_NETMASK_AIX=no,samba_cv_HAVE_NETMASK_AIX=cross)])
+if test x"$samba_cv_HAVE_NETMASK_AIX" = x"yes"; then
+ netmask=yes;AC_DEFINE(HAVE_NETMASK_AIX)
+fi
+fi
+
+AC_CACHE_CHECK([for trapdoor seteuid],samba_cv_HAVE_TRAPDOOR_UID,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/trapdoor.c"],
+ samba_cv_HAVE_TRAPDOOR_UID=no,samba_cv_HAVE_TRAPDOOR_UID=yes,:)])
+if test x"$samba_cv_HAVE_TRAPDOOR_UID" = x"yes"; then
+ AC_DEFINE(HAVE_TRAPDOOR_UID)
+fi
+
+AC_CACHE_CHECK([for shared mmap],samba_cv_HAVE_SHARED_MMAP,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/shared_mmap.c"],
+ samba_cv_HAVE_SHARED_MMAP=yes,samba_cv_HAVE_SHARED_MMAP=no,samba_cv_HAVE_SHARED_MMAP=cross)])
+if test x"$samba_cv_HAVE_SHARED_MMAP" = x"yes"; then
+ AC_DEFINE(HAVE_SHARED_MMAP)
+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 64 bit fcntl locking],samba_cv_HAVE_STRUCT_FLOCK64,[
+AC_TRY_RUN([
+#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
+
+AC_CACHE_CHECK([for sysv ipc],samba_cv_HAVE_SYSV_IPC,[
+AC_TRY_RUN([#include "${srcdir-.}/tests/sysv_ipc.c"],
+ samba_cv_HAVE_SYSV_IPC=yes,samba_cv_HAVE_SYSV_IPC=no,samba_cv_HAVE_SYSV_IPC=cross)])
+if test x"$samba_cv_HAVE_SYSV_IPC" = x"yes"; then
+ AC_DEFINE(HAVE_SYSV_IPC)
+fi
+
+#################################################
+# check for the AFS filesystem
+AC_MSG_CHECKING(whether to use AFS)
+AC_ARG_WITH(afs,
+[ --with-afs Include AFS support
+ --without-afs Don't include AFS support (default)],
+[ 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 auth system
+AC_MSG_CHECKING(whether to use DFS auth)
+AC_ARG_WITH(dfs,
+[ --with-dfs Include DFS support
+ --without-dfs Don't include DFS support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_DFS)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for Kerberos IV auth system
+AC_MSG_CHECKING(whether to use Kerberos IV)
+AC_ARG_WITH(krb4,
+[ --with-krb4=base-dir Include Kerberos IV support
+ --whithout-krb4 Don't include Kerbers IV support (default)],
+[ AC_MSG_RESULT(yes)
+ AC_DEFINE(KRB4_AUTH)
+ AC_CHECK_LIB(resolv, dn_expand)
+ LIBS="$LIBS -lkrb -ldes"
+ CFLAGS="$CFLAGS -I$withval/include"
+ LDFLAGS="$LDFLAGS -L$withval/lib"],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for automount support
+AC_MSG_CHECKING(whether to use AUTOMOUNT)
+AC_ARG_WITH(automount,
+[ --with-automount Include AUTOMOUNT support
+ --without-automount Don't include AUTOMOUNT support (default)],
+[ 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
+ --without-smbmount Don't include SMBMOUNT support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SMBMOUNT)
+ MPROGS="bin/smbmount bin/smbmnt bin/smbumount"
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ MPROGS=
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+ MPROGS=
+)
+
+#################################################
+# check for a LDAP password database
+AC_MSG_CHECKING(whether to use LDAP password database)
+AC_ARG_WITH(ldap,
+[ --with-ldap Include LDAP support
+ --without-ldap Don't include LDAP support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_LDAP)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for a NISPLUS password database
+AC_MSG_CHECKING(whether to use NISPLUS password database)
+AC_ARG_WITH(nisplus,
+[ --with-nisplus Include NISPLUS password database support
+ --without-nisplus Don't include NISPLUS password database support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_NISPLUS)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# 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
+ --without-nisplus-home Don't include NISPLUS_HOME support (default)],
+[ 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
+ --without-ssl Don't include SSL support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SSL)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for experimental mmap support
+AC_MSG_CHECKING(whether to use MMAP)
+AC_ARG_WITH(mmap,
+[ --with-mmap Include experimental MMAP support
+ --without-mmap Don't include MMAP support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_MMAP)
+ ;;
+ *)
+ 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
+ --without-syslog Don't include SYSLOG support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_SYSLOG)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+#################################################
+# check for experimental netatalk resource fork support
+AC_MSG_CHECKING(whether to support netatalk)
+AC_ARG_WITH(netatalk,
+[ --with-netatalk Include experimental Netatalk support
+ --without-netatalk Don't include experimental Netatalk support (default)],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_NETATALK)
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
+
+
+#################################################
+# 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([
+#include <sys/types.h>
+#include <sys/statvfs.h>
+ main ()
+ {
+ struct statvfs64 fsd;
+ exit (statfs64 (".", &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
+
+echo "checking configure summary"
+AC_TRY_RUN([#include "${srcdir-.}/tests/summary.c"],
+ echo "configure OK";,
+ AC_MSG_ERROR([summary failure. Aborting config]),:)
+
+AC_OUTPUT(include/stamp-h Makefile)
diff --git a/source/include/.cvsignore b/source/include/.cvsignore
new file mode 100644
index 00000000000..0e56cf2f8c1
--- /dev/null
+++ b/source/include/.cvsignore
@@ -0,0 +1 @@
+config.h
diff --git a/source/include/byteorder.h b/source/include/byteorder.h
index 899cd6c4991..3371fd24cbc 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
@@ -22,8 +22,98 @@
/*
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
+RIVAL(buf,pos) - like IVAL() 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
+
+it also defines lots of intermediate macros, just ignore those :-)
+
*/
+/* some switch macros that do both store and read to and from SMB buffers */
+
+#define RW_PCVAL(read,inbuf,outbuf,len) \
+ if (read) { PCVAL (inbuf,0,outbuf,len) } \
+ else { PSCVAL(inbuf,0,outbuf,len) }
+
+#define RW_PIVAL(read,inbuf,outbuf,len) \
+ if (read) { PIVAL (inbuf,0,outbuf,len) } \
+ else { PSIVAL(inbuf,0,outbuf,len) }
+
+#define RW_PSVAL(read,inbuf,outbuf,len) \
+ if (read) { PSVAL (inbuf,0,outbuf,len) } \
+ else { PSSVAL(inbuf,0,outbuf,len) }
+
+#define RW_CVAL(read, inbuf, outbuf, offset) \
+ if (read) (outbuf) = CVAL (inbuf,offset); \
+ else SCVAL(inbuf,offset,outbuf);
+
+#define RW_IVAL(read, inbuf, outbuf, offset) \
+ if (read) (outbuf)= IVAL (inbuf,offset); \
+ else SIVAL(inbuf,offset,outbuf);
+
+#define RW_SVAL(read, inbuf, outbuf, offset) \
+ if (read) (outbuf)= SVAL (inbuf,offset); \
+ else SSVAL(inbuf,offset,outbuf);
+
#undef CAREFUL_ALIGNMENT
/* we know that the 386 can handle misalignment and has the "right"
@@ -42,6 +132,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,24 +143,56 @@
#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
+
/* 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
+/* macros for reading / writing arrays */
+
+#define SMBMACRO(macro,buf,pos,val,len,size) \
+{ int l; for (l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }
+
+#define SSMBMACRO(macro,buf,pos,val,len,size) \
+{ int l; for (l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }
+
+/* reads multiple data from an SMB buffer */
+#define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
+#define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
+#define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
+#define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
+#define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
+#define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)
+
+/* stores multiple data in an SMB buffer */
+#define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
+#define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
+#define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
+#define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
+#define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
+#define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)
+
+
/* 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)))
@@ -78,3 +201,43 @@
#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+
+#define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
+ RW_PCVAL(read,inbuf,outbuf,len) \
+ DEBUG(5,("%s%04x %s: ", \
+ tab_depth(depth), PTR_DIFF(inbuf,base),string)); \
+ if (charmode) print_asc(5, (unsigned char*)(outbuf), (len)); else \
+ { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%02x ", (outbuf)[idx])); } } \
+ DEBUG(5,("\n"));
+
+#define DBG_RW_PSVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
+ RW_PSVAL(read,inbuf,outbuf,len) \
+ DEBUG(5,("%s%04x %s: ", \
+ tab_depth(depth), PTR_DIFF(inbuf,base),string)); \
+ if (charmode) print_asc(5, (unsigned char*)(outbuf), 2*(len)); else \
+ { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%04x ", (outbuf)[idx])); } } \
+ DEBUG(5,("\n"));
+
+#define DBG_RW_PIVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
+ RW_PIVAL(read,inbuf,outbuf,len) \
+ DEBUG(5,("%s%04x %s: ", \
+ tab_depth(depth), PTR_DIFF(inbuf,base),string)); \
+ if (charmode) print_asc(5, (unsigned char*)(outbuf), 4*(len)); else \
+ { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%08x ", (outbuf)[idx])); } } \
+ DEBUG(5,("\n"));
+
+#define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
+ RW_CVAL(read,inbuf,outbuf,0) \
+ DEBUG(5,("%s%04x %s: %02x\n", \
+ tab_depth(depth), PTR_DIFF(inbuf,base), string, outbuf));
+
+#define DBG_RW_SVAL(string,depth,base,read,inbuf,outbuf) \
+ RW_SVAL(read,inbuf,outbuf,0) \
+ DEBUG(5,("%s%04x %s: %04x\n", \
+ tab_depth(depth), PTR_DIFF(inbuf,base), string, outbuf));
+
+#define DBG_RW_IVAL(string,depth,base,read,inbuf,outbuf) \
+ RW_IVAL(read,inbuf,outbuf,0) \
+ DEBUG(5,("%s%04x %s: %08x\n", \
+ tab_depth(depth), PTR_DIFF(inbuf,base), string, outbuf));
+
diff --git a/source/include/charset.h b/source/include/charset.h
index 7091732223a..b6f79c03dde 100644
--- a/source/include/charset.h
+++ b/source/include/charset.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Character set 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
@@ -51,11 +51,25 @@ extern void charset_initialise(void);
#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 toupper(c) (upper_char_map[(c&0xff)] & 0xff)
+#define tolower(c) (lower_char_map[(c&0xff)] & 0xff)
+#define isupper(c) ((c&0xff) != tolower(c&0xff))
+#define islower(c) ((c&0xff) != toupper(c&0xff))
+#define isdoschar(c) (dos_char_map[(c&0xff)] != 0)
#define isspace(c) ((c)==' ' || (c) == '\t')
+
+/* this is used to determine if a character is safe to use in
+ something that may be put on a command line */
+#define issafe(c) (isalnum((c&0xff)) || strchr("-._",c))
#endif
+/* Dynamic codepage files defines. */
+
+/* Version id for dynamically loadable codepage files. */
+#define CODEPAGE_FILE_VERSION_ID 0x1
+/* Version 1 codepage file header size. */
+#define CODEPAGE_HEADER_SIZE 8
+/* Offsets for codepage file header entries. */
+#define CODEPAGE_VERSION_OFFSET 0
+#define CODEPAGE_CLIENT_CODEPAGE_OFFSET 2
+#define CODEPAGE_LENGTH_OFFSET 4
diff --git a/source/include/client.h b/source/include/client.h
new file mode 100644
index 00000000000..dde377f484b
--- /dev/null
+++ b/source/include/client.h
@@ -0,0 +1,107 @@
+/*
+ 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
+
+/*
+ * These definitions depend on smb.h
+ */
+
+typedef struct
+{
+ SMB_OFF_T size;
+ int 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;
+} file_info;
+
+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[24];
+};
+
+struct cli_state {
+ int fd;
+ int cnum;
+ int pid;
+ int mid;
+ int uid;
+ int protocol;
+ int sec_mode;
+ int rap_error;
+ int privilages;
+
+ fstring eff_name;
+ fstring desthost;
+ fstring user_name;
+ fstring 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;
+ unsigned char cryptkey[8];
+ uint32 sesskey;
+ int serverzone;
+ uint32 servertime;
+ int readbraw_supported;
+ int writebraw_supported;
+ int timeout;
+ int max_xmit;
+ char *outbuf;
+ char *inbuf;
+ int bufsize;
+ int initialised;
+ /*
+ * Only used in NT domain calls.
+ */
+ uint32 nt_error; /* NT RPC error code. */
+ uint16 nt_pipe_fnum; /* Pipe handle. */
+ unsigned char sess_key[16]; /* Current session key. */
+ DOM_CRED clnt_cred; /* Client credential. */
+ fstring mach_acct; /* MYNAME$. */
+ fstring srv_name_slash; /* \\remote server. */
+ fstring clnt_name_slash; /* \\local client. */
+};
+
+#endif /* _CLIENT_H */
diff --git a/source/include/config.h.in b/source/include/config.h.in
new file mode 100644
index 00000000000..1f1cb04e0bf
--- /dev/null
+++ b/source/include/config.h.in
@@ -0,0 +1,515 @@
+/* include/config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* 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 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 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 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_BROKEN_READDIR
+#undef HAVE_ERRNO_DECL
+#undef HAVE_LONGLONG
+#undef HAVE_OFF64_T
+#undef HAVE_REMSH
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UTIMBUF
+#undef ssize_t
+#undef ino_t
+#undef ssize_t
+#undef HAVE_CONNECT
+#undef HAVE_SHORT_INO_T
+#undef WITH_AFS
+#undef WITH_DFS
+#undef SUNOS5
+#undef SUNOS4
+#undef LINUX
+#undef AIX
+#undef IRIX
+#undef HPUX
+#undef QNX
+#undef SCO
+#undef OSF1
+#undef NEXT2
+#undef HAVE_SHARED_MMAP
+#undef HAVE_SYSV_IPC
+#undef HAVE_FCNTL_LOCK
+#undef HAVE_FTRUNCATE_EXTEND
+#undef HAVE_TRAPDOOR_UID
+#undef HAVE_ROOT
+#undef HAVE_UNION_SEMUN
+#undef HAVE_NETMASK_IFCONF
+#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_NETMASK_IFREQ
+#undef HAVE_NETMASK_AIX
+#undef HAVE_CRYPT
+#undef WITH_MMAP
+#undef WITH_SYSLOG
+#undef WITH_SSL
+#undef WITH_LDAP
+#undef WITH_NISPLUS
+#undef WITH_NISPLUS_HOME
+#undef WITH_AUTOMOUNT
+#undef WITH_SMBMOUNT
+#undef HAVE_PAM_AUTHENTICATE
+#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 HAVE_INO64_T
+#undef HAVE_STRUCT_FLOCK64
+#undef SIZEOF_INO_T
+#undef SIZEOF_OFF_T
+#undef STAT_STATVFS64
+#undef HAVE_LIBREADLINE
+#undef HAVE_KERNEL_OPLOCKS
+#undef HAVE_IRIX_SPECIFIC_CAPABILITIES
+#undef KRB4_AUTH
+
+/* 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 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 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 execl function. */
+#undef HAVE_EXECL
+
+/* Define if you have the fseek64 function. */
+#undef HAVE_FSEEK64
+
+/* 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 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 getgrnam function. */
+#undef HAVE_GETGRNAM
+
+/* 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 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 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 pam_authenticate function. */
+#undef HAVE_PAM_AUTHENTICATE
+
+/* 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 putprpwnam function. */
+#undef HAVE_PUTPRPWNAM
+
+/* 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 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 setgroups function. */
+#undef HAVE_SETGROUPS
+
+/* Define if you have the setluid function. */
+#undef HAVE_SETLUID
+
+/* 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 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 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 strpbrk function. */
+#undef HAVE_STRPBRK
+
+/* 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 vsnprintf function. */
+#undef HAVE_VSNPRINTF
+
+/* 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 <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 <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 <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Define if you have the <history.h> header file. */
+#undef HAVE_HISTORY_H
+
+/* Define if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_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/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_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/auth.h> header file. */
+#undef HAVE_RPC_AUTH_H
+
+/* Define if you have the <rpc/clnt.h> header file. */
+#undef HAVE_RPC_CLNT_H
+
+/* Define if you have the <rpc/types.h> header file. */
+#undef HAVE_RPC_TYPES_H
+
+/* Define if you have the <rpc/xdr.h> header file. */
+#undef HAVE_RPC_XDR_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_appl.h> header file. */
+#undef HAVE_SECURITY_PAM_APPL_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/capability.h> header file. */
+#undef HAVE_SYS_CAPABILITY_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/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/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/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/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/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 <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 dl library (-ldl). */
+#undef HAVE_LIBDL
+
+/* 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 readline library (-lreadline). */
+#undef HAVE_LIBREADLINE
+
+/* Define if you have the resolv library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
diff --git a/source/include/dlinklist.h b/source/include/dlinklist.h
new file mode 100644
index 00000000000..851bf01d380
--- /dev/null
+++ b/source/include/dlinklist.h
@@ -0,0 +1,56 @@
+/*
+ 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 */
+#define DLIST_REMOVE(list, p) \
+{ \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+}
+
+/* promote an element to the top of the list */
+#define DLIST_PROMOTE(list, p) \
+ DLIST_REMOVE(list, p) \
+ DLIST_ADD(list, p)
diff --git a/source/include/includes.h b/source/include/includes.h
index cc2bbbfad7c..2ec134b7c6f 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,920 +20,502 @@
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.
-*/
-
-/* the first OS dependent section is to setup what includes will be used.
- the main OS dependent section comes later on
-*/
-
-#ifdef ALTOS
-#define NO_UTIMEH
+#ifndef NO_CONFIG_H /* for some tests */
+#include "config.h"
#endif
+#include "local.h"
-#ifdef MIPS
-#define POSIX_H
-#define NO_UTIMEH
+#ifdef AIX
+#define DEFAULT_PRINTING PRINT_AIX
#endif
-#ifdef sun386
-#define NO_UTIMEH
+#ifdef HPUX
+#define DEFAULT_PRINTING PRINT_HPUX
#endif
-#ifdef NEXT2
-#define NO_UTIMEH
+#ifdef QNX
+#define DEFAULT_PRINTING PRINT_QNX
#endif
-#ifdef NEXT3_0
-#define NO_UTIMEH
-#define NO_UNISTDH
+#ifdef SUNOS4
+/* on SUNOS4 termios.h conflicts with sys/ioctl.h */
+#undef HAVE_TERMIOS_H
#endif
-#ifdef APOLLO
-#define NO_UTIMEH
-#define NO_SYSMOUNTH
-#define NO_UNISTDH
-#endif
-#ifdef AIX
-#define NO_SYSMOUNTH
+#include <sys/types.h>
+
+#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
#endif
-#ifdef M88K_R3
-#define SVR3H
-#define NO_RESOURCEH
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
#endif
-#ifdef DNIX
-#define NO_SYSMOUNTH
-#define NO_NETIFH
-#define NO_RESOURCEH
-#define PRIME_NMBD 0
-#define NO_SETGROUPS
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
+#include <stdio.h>
+#include <stddef.h>
-#ifdef ISC
-#define SYSSTREAMH
-#define NO_RESOURCEH
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
#endif
-#ifdef QNX
-#define NO_RESOURCEH
-#define NO_SYSMOUNTH
-#define USE_MMAP 1
-#ifdef __386__
- #define __i386__
-#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
#endif
-#ifdef NEWS42
-#define NO_UTIMEH
-#define NO_STRFTIME
-#define NO_UTIMBUF
-#define REPLACE_MKTIME
-#define NO_TM_NAME
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
#endif
-#ifdef OS2
-#define NO_SYSMOUNTH
-#define NO_NETIFH
+#ifdef HAVE_STRING_H
+#include <string.h>
#endif
-#ifdef LYNX
-#define NO_SYSMOUNTH
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
-#if (defined(SHADOW_PWD)||defined(OSF1_ENH_SEC)||defined(SecureWare)||defined(PWDAUTH))
-#define PASSWORD_LENGTH 16
+#ifdef HAVE_MALLOC_H
+#include <malloc.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>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
#else
-#include <stdlib.h>
+#ifdef HAVE_SYS_FCNTL_H
+#include <sys/fcntl.h>
#endif
-#include <ctype.h>
-#include <time.h>
-#ifndef NO_UTIMEH
-#include <utime.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>
+#include <sys/stat.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
#endif
-#include <sys/socket.h>
+#ifdef HAVE_SYS_IOCTL_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>
-#endif
-#ifndef NO_SYSMOUNTH
-#include <sys/mount.h>
#endif
-#include <pwd.h>
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-#ifndef NO_UNISTDH
-#include <unistd.h>
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
#endif
+
+#include <signal.h>
+
+#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
-#ifdef SYSSTREAMH
-#include <sys/stream.h>
#endif
-#ifndef NO_NETIFH
-#ifdef POSIX_H
-#include <bsd/net/if.h>
-#else
-#include <net/if.h>
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
#endif
-
-#if USE_MMAP
-#include <sys/mman.h>
+#ifdef HAVE_SYS_ID_H
+#include <sys/id.h>
#endif
-#if defined(GETPWANAM)
-#include <sys/types.h>
-#include <sys/label.h>
-#include <sys/audit.h>
-#include <pwdadj.h>
-#endif
+#include <errno.h>
-#if defined(SHADOW_PWD) && !defined(NETBSD) && !defined(CONVEX)
-#include <shadow.h>
+#ifdef HAVE_UTIME_H
+#include <utime.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>
-#endif
-#include <mntent.h>
-#else
-#include <sys/quota.h>
-#ifndef CRAY
-#include <devnm.h>
-#else
-#include <mntent.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
#endif
+
+#ifdef HAVE_SYS_MODE_H
+/* apparently AIX needs this for S_ISLNK */
+#ifndef S_ISLNK
+#include <sys/mode.h>
#endif
#endif
-#ifdef SYSLOG
-#include <syslog.h>
+#ifdef HAVE_GLOB
+#include <glob.h>
#endif
+#include <pwd.h>
+#include <grp.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.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>
-#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
-#endif
-#endif
-#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/file.h>
-#ifdef SUNOS4
-#define SIGNAL_CAST (void (*)(int))
+#ifdef HAVE_NETINET_TCP_H
#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;
-#else
-#include <utime.h>
-#define NO_STRERROR
-#endif
-#define REPLACE_GETPASS
-#define BSD_TERMIO
#endif
-
-#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>
-#include <netinet/tcp.h>
-#include <netinet/ip.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <rpcsvc/ypclnt.h>
-#include <crypt.h>
+#ifdef HAVE_TERMIOS_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
-
-#ifdef ULTRIX
-#include <strings.h>
-#include <nfs/nfs_clnt.h>
-#include <nfs/vfs.h>
-#include <netinet/tcp.h>
-#ifdef ULTRIX_AUTH
-#include <auth.h>
-#endif
-char *getwd(char *);
-#define NOSTRDUP
-#ifdef __STDC__
-#define SIGNAL_CAST (void(*)(int))
-#endif
-#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_SHARED_MMAP
+#include <sys/mman.h>
#endif
-#ifdef SGI
-#include <netinet/tcp.h>
-#include <sys/statfs.h>
-#include <string.h>
-#include <signal.h>
-#ifndef SYSV
-#define SYSV
+#ifdef HAVE_SYSV_IPC
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
#endif
-#define SIGNAL_CAST (void (*)())
-#define STATFS4
-#define USE_WAITPID
-#define USE_DIRECT
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.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_SYS_MOUNT_H
+#include <sys/mount.h>
#endif
-#define SIGNAL_CAST (void (*)())
-#define USE_STATVFS
-#define USE_WAITPID
+
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
#endif
+#ifdef HAVE_SYS_FS_S5PARAM_H
+#include <sys/fs/s5param.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 */
+#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY)
+#include <sys/filsys.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+#ifdef HAVE_DUSTAT_H
+#include <sys/dustat.h>
+#endif
-#ifdef DGUX
-#include <string.h>
-#include <dirent.h>
-#include <sys/statfs.h>
+#ifdef HAVE_SYS_STATVFS_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
#endif
-
-#ifdef SVR4
-#include <string.h>
-#include <sys/dir.h>
-#include <dirent.h>
-#include <sys/statfs.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
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
#endif
+#ifdef HAVE_GETPWANAM
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.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_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
-
-
-#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 */
-
+#endif /* HAVE_SYS_SECURITY_H */
-
-#ifdef BSDI
-#include <string.h>
-#include <netinet/tcp.h>
-#define SIGNAL_CAST (void (*)())
-#define USE_DIRECT
+#ifdef HAVE_COMPAT_H
+#include <compat.h>
#endif
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#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
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+#ifndef uchar
+#define uchar unsigned char
+#endif
-#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
+#ifdef HAVE_UNSIGNED_CHAR
+#define schar signed char
+#else
+#define schar char
+#endif
+/*
+ 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.
+*/
-#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
+#ifndef uint8
+#define uint8 unsigned char
#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
+#ifndef int16
+#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 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
+#ifndef uint16
+#define uint16 unsigned int16
#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
-
-
-#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
+#ifndef int32
+#if (SIZEOF_INT == 4)
+#define int32 int
+#elif (SIZEOF_LONG == 4)
+#define int32 long
+#elif (SIZEOF_SHORT == 4)
+#define int32 short
+#endif
#endif
+#ifndef uint32
+#define uint32 unsigned int32
+#endif
+/*
+ * Types for devices, inodes and offsets.
+ */
-#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 SMB_DEV_T
+#define SMB_DEV_T dev_t
#endif
+/*
+ * Setup the correctly sized inode type.
+ */
-
-#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>
-#endif
-#ifdef NETGROUP
-#include <rpcsvc/ypclnt.h>
-#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
-#else
-#ifndef EVEREST
-#define USE_IFREQ
-#endif
+#ifndef SMB_INO_T
+# ifdef HAVE_INO64_T
+# define SMB_INO_T ino64_t
+# else
+# define SMB_INO_T ino_t
+# endif
#endif
-#define STATFS4
-#define NO_FSYNC
-#ifndef EVEREST
-#define NO_INITGROUPS
+
+#ifndef LARGE_SMB_INO_T
+# if defined(HAVE_INO64_T) || (defined(SIZEOF_INO_T) && (SIZEOF_INO_T == 8))
+# define LARGE_SMB_INO_T 1
+# endif
#endif
-#define HAVE_PATHCONF
-#define NO_GETRLIMIT
+
+#ifndef SMB_OFF_T
+# ifdef HAVE_OFF64_T
+# define SMB_OFF_T off64_t
+# else
+# define SMB_OFF_T off_t
+# endif
#endif
+#define SMB_OFF_T_BITS (sizeof(SMB_OFF_T)*8)
+/*
+ * Set the define that tells us if we can do 64 bit
+ * NT SMB calls.
+ */
-/* 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 LARGE_SMB_OFF_T
+# if defined(HAVE_OFF64_T) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8))
+# define LARGE_SMB_OFF_T 1
+# endif
#endif
+#ifdef LARGE_SMB_OFF_T
+#define SOFF_T(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32))
+#else
+#define SOFF_T(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0))
+#endif
+/*
+ * Type for stat structure.
+ */
-#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_STRUCT_STAT
+# if defined(HAVE_STAT64) && defined(HAVE_OFF64_T)
+# define SMB_STRUCT_STAT struct stat64
+# else
+# define SMB_STRUCT_STAT struct stat
+# endif
#endif
+/*
+ * Defines for 64 bit fcntl locks.
+ */
-
-#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
+#ifndef SMB_STRUCT_FLOCK
+# if 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_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_SETLKW F_SETLKW64
+# else
+# define SMB_F_SETLKW F_SETLKW
+# 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
+#ifndef SMB_F_SETLK
+# if defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_SETLK F_SETLK64
+# else
+# define SMB_F_SETLK F_SETLK
+# endif
#endif
+#ifndef SMB_F_GETLK
+# if defined(HAVE_STRUCT_FLOCK64) && defined(HAVE_OFF64_T)
+# define SMB_F_GETLK F_GETLK64
+# else
+# define SMB_F_GETLK F_GETLK
+# endif
+#endif
-#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
+#if defined(HAVE_LONGLONG)
+#define SMB_BIG_UINT unsigned long long
+#define SMB_BIG_INT long long
+#else
+#define SMB_BIG_UINT unsigned long
+#define SMB_BIG_INT long
#endif
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
-#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 MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
#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
+#ifndef HAVE_STRERROR
+extern char *sys_errlist[];
+#define strerror(i) sys_errlist[i]
#endif
+#ifndef HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+#endif
-#ifdef NEWS42
-#include <string.h>
-#include <dirent.h>
-#include <sys/vfs.h>
-#include <sys/timeb.h>
-typedef int mode_t;
+#ifndef HAVE_ERRNO_DECL
+extern int errno;
#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
+#ifdef HAVE_BROKEN_GETGROUPS
+#define GID_T int
+#else
+#define GID_T gid_t
#endif
-/*******************************************************************
-end of the platform specific sections
-********************************************************************/
+/* Lists, trees, caching, datbase... */
+#include "ubi_sLinkList.h"
+#include "ubi_dLinkList.h"
+#include "dlinklist.h"
-#ifdef SecureWare
-#define NEED_AUTH_PARAMETERS
-#endif
+#ifndef UBI_BINTREE_H
+#include "ubi_Cache.h"
+#endif /* UBI_BINTREE_H */
-#ifdef REPLACE_GETPASS
-extern char *getsmbpass(char *);
-#define getpass(s) getsmbpass(s)
-#endif
+#include "version.h"
+#include "smb.h"
+#include "nameserv.h"
-#ifdef REPLACE_INNETGR
-#define innetgr(group,host,user,dom) InNetGr(group,host,user,dom)
-#endif
+#include "byteorder.h"
-#ifndef FD_SETSIZE
-#define FD_SETSIZE 255
-#endif
+#include "kanji.h"
+#include "charset.h"
-#ifndef MAXINT
-#define MAXINT ((((unsigned)1)<<(sizeof(int)*8-1))-1)
-#endif
+#include "nterr.h"
-#ifndef __STDC__
-#define const
+#ifndef MAXCODEPAGELINES
+#define MAXCODEPAGELINES 256
#endif
-/* Now for some other grungy stuff */
-#ifdef NO_GETSPNAM
-struct spwd { /* fake shadow password structure */
- char *sp_pwdp;
-};
-#endif
+/***** automatically generated prototypes *****/
+#include "proto.h"
-#ifndef HAVE_BZERO
-#ifndef bzero
-#define bzero(p,s) memset(p,0,s)
-#endif
-#endif
+#ifdef strcpy
+#undef strcpy
+#endif /* strcpy */
+#define strcpy(dest,src) __ERROR__XX__NEVER_USE_STRCPY___;
-#ifndef HAVE_MEMMOVE
-#ifndef memmove
-#define memmove(d,s,n) MemMove(d,s,n)
-#endif
-#endif
+#ifdef strcat
+#undef strcat
+#endif /* strcat */
+#define strcat(dest,src) __ERROR__XX__NEVER_USE_STRCAT___;
-#ifdef USE_DIRECT
-#include <sys/dir.h>
-#endif
+#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)
-/* some unixes have ENOTTY instead of TIOCNOTTY */
-#ifndef TIOCNOTTY
-#ifdef ENOTTY
-#define TIOCNOTTY ENOTTY
+#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(SYSV)
+#define SYSV 1
#endif
-/* if undefined then use bsd or sysv printing */
#ifndef DEFAULT_PRINTING
#ifdef SYSV
#define DEFAULT_PRINTING PRINT_SYSV
@@ -942,213 +524,146 @@ struct spwd { /* fake shadow password structure */
#endif
#endif
-
-#ifdef AFS_AUTH
-#include <afs/stds.h>
-#include <afs/kautils.h>
-#endif
-
-#ifdef DFS_AUTH
-#include <dce/dce_error.h>
-#include <dce/sec_login.h>
-#endif
-
-#ifdef NO_UTIMBUF
-struct utimbuf {
- time_t actime;
- time_t modtime;
-};
+#ifndef SIGCLD
+#define SIGCLD SIGCHLD
#endif
-#ifdef NO_STRERROR
-#ifndef strerror
-extern char *sys_errlist[];
-#define strerror(i) sys_errlist[i]
-#endif
+#if (defined(HAVE_SYSV_IPC) || defined(HAVE_SHARED_MMAP))
+#define FAST_SHARE_MODES 1
#endif
-#ifndef perror
-#define perror(m) printf("%s: %s\n",m,strerror(errno))
+#ifndef MAP_FILE
+#define MAP_FILE 0
#endif
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 255
+#ifdef HAVE_SYSV_IPC
+#ifndef HAVE_UNION_SEMUN
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
#endif
-
-#include "version.h"
-#include "smb.h"
-#include "byteorder.h"
-#ifdef SMB_PASSWD
-#include "smbpass.h"
#endif
-#include "kanji.h"
-#include "charset.h"
-
-#ifndef S_IFREG
-#define S_IFREG 0100000
+#if (!defined(WITH_NISPLUS) && !defined(WITH_LDAP))
+#define USE_SMBPASS_DB 1
#endif
-#ifndef S_ISREG
-#define S_ISREG(x) ((S_IFREG & x)!=0)
+#if defined(HAVE_PUTPRPWNAM) && defined(AUTH_CLEARTEXT_SEG_CHARS)
+#define OSF1_ENH_SEC 1
#endif
-#ifndef S_ISDIR
-#define S_ISDIR(x) ((S_IFDIR & x)!=0)
+#if defined(HAVE_PAM_AUTHENTICATE) && defined(HAVE_SECURITY_PAM_APPL_H)
+#define HAVE_PAM 1
#endif
-#ifdef UFC_CRYPT
-#define crypt ufc_crypt
+#if defined(HAVE_YP_GET_DEFAULT_DOMAIN)
+#define HAVE_NETGROUP 1
#endif
-#ifdef REPLACE_STRLEN
-#define strlen(s) Strlen(s)
+#if defined (HAVE_NETGROUP) && defined(HAVE_RPCSVC_YPCLNT_H)
+#include "rpcsvc/ypclnt.h"
#endif
-#ifdef REPLACE_STRSTR
-#define strstr(s,p) Strstr(s,p)
+#ifndef ALLOW_CHANGE_PASSWORD
+#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
+#define ALLOW_CHANGE_PASSWORD 1
#endif
-
-#ifdef REPLACE_MKTIME
-#define mktime(t) Mktime(t)
#endif
-#ifndef NGROUPS_MAX
-#define NGROUPS_MAX 128
+/* 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 EDQUOT
-#define EDQUOT ENOSPC
+#ifdef REPLACE_INET_NTOA
+#define inet_ntoa rep_inet_ntoa
#endif
-#ifndef HAVE_GETGRNAM
-#define HAVE_GETGRNAM 1
+#ifndef HAVE_PIPE
+#define SYNC_DNS 1
#endif
-#ifndef SOL_TCP
-#define SOL_TCP 6
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
#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 SEEK_SET
+#define SEEK_SET 0
#endif
-/* maybe this unix doesn't separate RD and WR locks? */
-#ifndef F_RDLCK
-#define F_RDLCK F_WRLCK
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001
#endif
-#ifndef ENOTSOCK
-#define ENOTSOCK EINVAL
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
#endif
-#ifndef SIGCLD
-#define SIGCLD SIGCHLD
-#endif
-
-#ifndef HAVE_FCNTL_LOCK
-#define HAVE_FCNTL_LOCK 1
-#endif
-
-#ifndef WAIT3_CAST2
-#define WAIT3_CAST2 (struct rusage *)
-#endif
-
-#ifndef WAIT3_CAST1
-#define WAIT3_CAST1 (int *)
+#ifndef HAVE_CRYPT
+#define crypt ufc_crypt
#endif
-#ifndef QSORT_CAST
-#define QSORT_CAST (int (*)())
+#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID)
+#define ULTRIX_AUTH 1
#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
+#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
-/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
-#ifndef errno
-extern int errno;
-#endif
-
-
-#ifdef NO_EID
-#define geteuid() getuid()
-#define getegid() getgid()
-#define seteuid(x) setuid(x)
-#define setegid(x) setgid(x)
+#ifndef HAVE_STRDUP
+char *strdup(const char *s);
#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 */
-
-#ifdef NOSTRCASECMP
-#define strcasecmp(s1,s2) StrCaseCmp(s1,s2)
-#define strncasecmp(s1,s2,n) StrnCaseCmp(s1,s2,n)
+#ifndef HAVE_MEMMOVE
+void *memmove(void *dest,const void *src,int size);
#endif
-#ifndef strcpy
-#define strcpy(dest,src) StrCpy(dest,src)
+#ifndef HAVE_INITGROUPS
+int initgroups(char *name,gid_t id);
#endif
-
-/* possibly wrap the malloc calls */
-#if WRAP_MALLOC
-
-/* undo the old malloc def if necessary */
-#ifdef malloc
-#define xx_old_malloc malloc
-#undef malloc
+#ifndef HAVE_RENAME
+int rename(const char *zfrom, const char *zto);
#endif
-#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
-
-/* undo the old realloc def if necessary */
-#ifdef realloc
-#define xx_old_realloc realloc
-#undef realloc
+#ifndef HAVE_MKTIME
+time_t mktime(struct tm *t);
#endif
-#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
-
-/* undo the old free def if necessary */
-#ifdef free
-#define xx_old_free free
-#undef free
+#ifndef HAVE_FTRUNCATE
+int ftruncate(int f,long l);
#endif
-#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);
-
+#if (defined(HAVE_SETRESUID) && !defined(HAVE_SETRESUID_DECL))
+/* stupid glibc */
+int setresuid(uid_t ruid, uid_t euid, uid_t suid);
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
#endif
-
-#if WRAP_MEMCPY
-/* undo the old memcpy def if necessary */
-#ifdef memcpy
-#define xx_old_memcpy memcpy
-#undef memcpy
+#if !defined(HAVE_BZERO) && defined(HAVE_MEMSET)
+#define bzero(a,b) memset((a),'\0',(b))
#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);
+#ifdef REPLACE_GETPASS
+#define getpass(prompt) getsmbpass((prompt))
#endif
-#endif
+#endif /* _INCLUDES_H */
diff --git a/source/include/kanji.h b/source/include/kanji.h
index 4f18305c637..db3731e41b1 100644
--- a/source/include/kanji.h
+++ b/source/include/kanji.h
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ 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
@@ -22,12 +22,11 @@
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>
+ and add upper/lower case conversion 1997.8.21
*/
#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) \
@@ -37,6 +36,22 @@
&& ((unsigned char) (c)) != 0x7f)
#define is_kana(c) ((0xa0 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xdf))
+/* case conversion */
+#define is_sj_upper2(c) \
+ ((0x60 <= (unsigned char) (c)) && ((unsigned char) (c) <= 0x79))
+#define is_sj_lower2(c) \
+ ((0x81 <= (unsigned char) (c)) && ((unsigned char) (c) <= 0x9A))
+#define sjis_alph 0x82
+#define is_sj_alph(c) (sjis_alph == (unsigned char) (c))
+#define is_sj_upper(c1, c2) (is_sj_alph (c1) && is_sj_upper2 (c2))
+#define is_sj_lower(c1, c2) (is_sj_alph (c1) && is_sj_lower2 (c2))
+#define sj_toupper2(c) \
+ (is_sj_lower2 (c) ? ((int) ((unsigned char) (c) - 0x81 + 0x60)) : \
+ ((int) (unsigned char) (c)))
+#define sj_tolower2(c) \
+ (is_sj_upper2 (c) ? ((int) ((unsigned char) (c) - 0x60 + 0x81)) : \
+ ((int) (unsigned char) (c)))
+
#ifdef _KANJI_C_
/* FOR EUC CODE */
#define euc_kana (0x8e)
@@ -88,23 +103,58 @@
#define bin2hex(x) \
( (((int) (x)) >= 10)? (((int) (x))-10 + (int) 'a'): (((int) (x)) + (int) '0') )
-#else /* not _KANJI_C_ */
+/* For Hangul (Korean - code page 949). */
+#define is_hangul(c) ((0x81 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xfd))
-extern char* (*_dos_to_unix) (const char *str, BOOL overwrite);
-extern char* (*_unix_to_dos) (const char *str, BOOL overwrite);
+/* For traditional Chinese (known as Big5 encoding - code page 950). */
+#define is_big5_c1(c) ((0xa1 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xf9))
-#define unix_to_dos (*_unix_to_dos)
-#define dos_to_unix (*_dos_to_unix)
+/* For simplified Chinese (code page - 936). */
+#define is_simpch_c1(c) ((0xa1 <= ((unsigned char) (c)) && ((unsigned char) (c)) <= 0xf7))
-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);
+#else /* not _KANJI_C_ */
-#define strchr sj_strchr
-#define strrchr sj_strrchr
-#define strstr sj_strstr
-#define strtok sj_strtok
+/*
+ * The following is needed for AIX systems that have
+ * their own #defines for strchr, strrchr, strstr
+ * and strtok.
+ */
+
+#ifdef strchr
+#undef strchr
+#endif /* strchr */
+
+#ifdef strrchr
+#undef strrchr
+#endif /* strrchr */
+
+#ifdef strstr
+#undef strstr
+#endif /* strstr */
+
+#ifdef strtok
+#undef strtok
+#endif /* strtok */
+
+/* Ensure we use our definitions in all other files than kanji.c. */
+
+/* Function pointers we will replace. */
+extern char *(*multibyte_strchr)(char *s, int c);
+extern char *(*multibyte_strrchr)(char *s, int c);
+extern char *(*multibyte_strstr)(char *s1, char *s2);
+extern char *(*multibyte_strtok)(char *s1, char *s2);
+extern char *(*_dos_to_unix)(char *str, BOOL overwrite);
+extern char *(*_unix_to_dos)(char *str, BOOL overwrite);
+extern BOOL (*is_multibyte_char)(char c);
+extern int (*_skip_multibyte_char)(char c);
+
+#define strchr(s1, c) ((*multibyte_strchr)((s1), (c)))
+#define strrchr(s1, c) ((*multibyte_strrchr)((s1), (c)))
+#define strstr(s1, s2) ((*multibyte_strstr)((s1), (s2)))
+#define strtok(s1, s2) ((*multibyte_strtok)((s1), (s2)))
+#define dos_to_unix(x,y) ((*_dos_to_unix)((x), (y)))
+#define unix_to_dos(x,y) ((*_unix_to_dos)((x), (y)))
+#define skip_multibyte_char(c) ((*_skip_multibyte_char)((c)))
#endif /* _KANJI_C_ */
@@ -118,13 +168,4 @@ extern char *sj_strstr (const char *s1, const char *s2);
#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/local.h b/source/include/local.h
index 2775453e150..6903e5854f6 100644
--- a/source/include/local.h
+++ b/source/include/local.h
@@ -1,7 +1,15 @@
+/* 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
+
/* 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,53 +25,44 @@
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 64
+
+/* define what facility to use for syslog */
+#ifndef SYSLOG_FACILITY
+#define SYSLOG_FACILITY LOG_DAEMON
+#endif
+
+/* Default size of shared memory used for share mode locking */
+#ifndef SHMEM_SIZE
+#define SHMEM_SIZE (1024*1024)
+#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
+/* this should have been set in the Makefile */
#define LOCKDIR "/tmp/samba"
#endif
/* 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
@@ -79,15 +78,14 @@
/* 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"
+/* what default type of filesystem do we want this to show up as in a
+ NT file manager window? */
+#define FSTYPE_STRING "NTFS"
-/* 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)
+/* the default guest account - normally set in the Makefile or smb.conf */
+#ifndef GUEST_ACCOUNT
+#define GUEST_ACCOUNT "nobody"
+#endif
/* do you want smbd to send a 1 byte packet to nmbd to trigger it to start
when smbd starts? */
@@ -127,12 +125,15 @@
/* the size of the uid cache used to reduce valid user checks */
#define UID_CACHE_SIZE 4
+/* if mmap is enabled, then this is the maximum size of file to use
+ the mmap code on. We don't want to mmap huge files as virtual
+ address spaces are limited */
+#define MAX_MMAP_SIZE (100*0x100000)
+
/* 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 (60)
#define IDLE_CLOSED_TIMEOUT (60)
#define DPTR_IDLE_TIMEOUT (120)
#define SMBD_SELECT_LOOP (10)
@@ -151,17 +152,37 @@
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
-
#define SMB_ALIGNMENT 1
/* shall we support browse requests via a FIFO to nmbd? */
#define ENABLE_FIFO 1
+/* how long to wait for a socket connect to happen */
+#define LONG_CONNECT_TIMEOUT 30
+#define SHORT_CONNECT_TIMEOUT 5
+
+/* the default netbios keepalive timeout */
+#define DEFAULT_KEEPALIVE 300
+
+/* 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/"
#endif
diff --git a/source/include/nameserv.h b/source/include/nameserv.h
index 168dd4ba866..e3a1d740a74 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,393 @@
*/
-#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 */
+};
+
+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;
+};
+
+/* 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. */
};
-/* a resource record */
+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 +418,7 @@ struct res_rec {
char rdata[MAX_DGRAM_SIZE];
};
-/* define a nmb packet. */
+/* An nmb packet. */
struct nmb_packet
{
struct {
@@ -115,7 +451,8 @@ struct nmb_packet
};
-/* 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 +473,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 +492,74 @@ 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 QUERYFORPDC_R 12 /* Response to Query for PDC. */
+#define SAMLOGON 18
+#define SAMLOGON_R 19
+
+
+/* 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)
+
+/* Types of machine we can announce as. */
+#define ANNOUNCE_AS_NT 1
+#define ANNOUNCE_AS_WIN95 2
+#define ANNOUNCE_AS_WFW 3
+
+/* 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/ntdomain.h b/source/include/ntdomain.h
new file mode 100644
index 00000000000..efe7e663a04
--- /dev/null
+++ b/source/include/ntdomain.h
@@ -0,0 +1,132 @@
+/*
+ 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"
+
+/* 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"
+
+/*
+ * A bunch of stuff that was put into smb.h
+ * in the NTDOM branch - it didn't belong there.
+ */
+
+typedef struct
+{
+ struct mem_buf *data; /* memory buffer */
+ uint32 offset; /* offset currently being accessed in memory buffer */
+ uint8 align; /* data alignment */
+ BOOL io; /* parsing in or out of data stream */
+
+} prs_struct;
+
+typedef struct pipes_struct
+{
+ struct pipes_struct *next, *prev;
+ int pnum;
+ connection_struct *conn;
+ int uid;
+ BOOL open; /* open connection */
+ uint16 device_state;
+ fstring name;
+ fstring pipe_srv_name;
+
+ prs_struct rhdr; /* output header */
+ prs_struct rdata; /* output data */
+ prs_struct rauth; /* output authentication verifier */
+
+ RPC_HDR hdr;
+ RPC_HDR_BA hdr_ba;
+ RPC_HDR_RB hdr_rb;
+ RPC_HDR_REQ hdr_req;
+ RPC_HDR_RESP hdr_resp;
+
+ RPC_AUTH_NTLMSSP_REQ ntlmssp_req;
+ RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
+
+ uint32 file_offset;
+ uint32 hdr_offsets;
+ uint32 frag_len_left;
+ uint32 next_frag_start;
+
+} pipes_struct;
+
+struct api_struct
+{
+ char *name;
+ uint8 opnum;
+ void (*fn) (int uid, prs_struct*, prs_struct*);
+};
+
+struct mem_desc
+{
+ /* array memory offsets */
+ uint32 start;
+ uint32 end;
+};
+
+struct mem_buf
+{
+ BOOL dynamic; /* True iff data has been dynamically allocated
+ (and therefore can be freed) */
+ char *data;
+ uint32 data_size;
+ uint32 data_used;
+
+ uint32 margin; /* safety margin when reallocing. */
+ /* this can be abused quite nicely */
+ uint8 align; /* alignment of data structures (smb, dce/rpc, udp etc) */
+
+ struct mem_desc offset;
+
+ struct mem_buf *next;
+};
+
+typedef struct
+{
+ uint32 rid;
+ char *name;
+
+} rid_name;
+
+struct acct_info
+{
+ fstring acct_name; /* account name */
+ uint32 smb_userid; /* domain-relative RID */
+};
+
+#endif /* _NT_DOMAIN_H */
+
diff --git a/source/include/nterr.h b/source/include/nterr.h
new file mode 100644
index 00000000000..a94464a013e
--- /dev/null
+++ b/source/include/nterr.h
@@ -0,0 +1,507 @@
+/* these are the NT error codes less than 1000. They are here for when
+ we start supporting NT error codes in Samba. They were extracted
+ using a loop in smbclient then printing a netmon sniff to a file */
+
+#define NT_STATUS_UNSUCCESSFUL (1)
+#define NT_STATUS_NOT_IMPLEMENTED (2)
+#define NT_STATUS_INVALID_INFO_CLASS (3)
+#define NT_STATUS_INFO_LENGTH_MISMATCH (4)
+#define NT_STATUS_ACCESS_VIOLATION (5)
+#define STATUS_BUFFER_OVERFLOW (5)
+#define NT_STATUS_IN_PAGE_ERROR (6)
+#define NT_STATUS_PAGEFILE_QUOTA (7)
+#define NT_STATUS_INVALID_HANDLE (8)
+#define NT_STATUS_BAD_INITIAL_STACK (9)
+#define NT_STATUS_BAD_INITIAL_PC (10)
+#define NT_STATUS_INVALID_CID (11)
+#define NT_STATUS_TIMER_NOT_CANCELED (12)
+#define NT_STATUS_INVALID_PARAMETER (13)
+#define NT_STATUS_NO_SUCH_DEVICE (14)
+#define NT_STATUS_NO_SUCH_FILE (15)
+#define NT_STATUS_INVALID_DEVICE_REQUEST (16)
+#define NT_STATUS_END_OF_FILE (17)
+#define NT_STATUS_WRONG_VOLUME (18)
+#define NT_STATUS_NO_MEDIA_IN_DEVICE (19)
+#define NT_STATUS_UNRECOGNIZED_MEDIA (20)
+#define NT_STATUS_NONEXISTENT_SECTOR (21)
+#define NT_STATUS_MORE_PROCESSING_REQUIRED (22)
+#define NT_STATUS_NO_MEMORY (23)
+#define NT_STATUS_CONFLICTING_ADDRESSES (24)
+#define NT_STATUS_NOT_MAPPED_VIEW (25)
+#define NT_STATUS_UNABLE_TO_FREE_VM (26)
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION (27)
+#define NT_STATUS_INVALID_SYSTEM_SERVICE (28)
+#define NT_STATUS_ILLEGAL_INSTRUCTION (29)
+#define NT_STATUS_INVALID_LOCK_SEQUENCE (30)
+#define NT_STATUS_INVALID_VIEW_SIZE (31)
+#define NT_STATUS_INVALID_FILE_FOR_SECTION (32)
+#define NT_STATUS_ALREADY_COMMITTED (33)
+#define NT_STATUS_ACCESS_DENIED (34)
+#define NT_STATUS_BUFFER_TOO_SMALL (35)
+#define NT_STATUS_OBJECT_TYPE_MISMATCH (36)
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION (37)
+#define NT_STATUS_INVALID_DISPOSITION (38)
+#define NT_STATUS_UNWIND (39)
+#define NT_STATUS_BAD_STACK (40)
+#define NT_STATUS_INVALID_UNWIND_TARGET (41)
+#define NT_STATUS_NOT_LOCKED (42)
+#define NT_STATUS_PARITY_ERROR (43)
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM (44)
+#define NT_STATUS_NOT_COMMITTED (45)
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES (46)
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG (47)
+#define NT_STATUS_INVALID_PARAMETER_MIX (48)
+#define NT_STATUS_INVALID_QUOTA_LOWER (49)
+#define NT_STATUS_DISK_CORRUPT_ERROR (50)
+#define NT_STATUS_OBJECT_NAME_INVALID (51)
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND (52)
+#define NT_STATUS_OBJECT_NAME_COLLISION (53)
+#define NT_STATUS_HANDLE_NOT_WAITABLE (54)
+#define NT_STATUS_PORT_DISCONNECTED (55)
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED (56)
+#define NT_STATUS_OBJECT_PATH_INVALID (57)
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND (58)
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD (59)
+#define NT_STATUS_DATA_OVERRUN (60)
+#define NT_STATUS_DATA_LATE_ERROR (61)
+#define NT_STATUS_DATA_ERROR (62)
+#define NT_STATUS_CRC_ERROR (63)
+#define NT_STATUS_SECTION_TOO_BIG (64)
+#define NT_STATUS_PORT_CONNECTION_REFUSED (65)
+#define NT_STATUS_INVALID_PORT_HANDLE (66)
+#define NT_STATUS_SHARING_VIOLATION (67)
+#define NT_STATUS_QUOTA_EXCEEDED (68)
+#define NT_STATUS_INVALID_PAGE_PROTECTION (69)
+#define NT_STATUS_MUTANT_NOT_OWNED (70)
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED (71)
+#define NT_STATUS_PORT_ALREADY_SET (72)
+#define NT_STATUS_SECTION_NOT_IMAGE (73)
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED (74)
+#define NT_STATUS_THREAD_IS_TERMINATING (75)
+#define NT_STATUS_BAD_WORKING_SET_LIMIT (76)
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP (77)
+#define NT_STATUS_SECTION_PROTECTION (78)
+#define NT_STATUS_EAS_NOT_SUPPORTED (79)
+#define NT_STATUS_EA_TOO_LARGE (80)
+#define NT_STATUS_NONEXISTENT_EA_ENTRY (81)
+#define NT_STATUS_NO_EAS_ON_FILE (82)
+#define NT_STATUS_EA_CORRUPT_ERROR (83)
+#define NT_STATUS_FILE_LOCK_CONFLICT (84)
+#define NT_STATUS_LOCK_NOT_GRANTED (85)
+#define NT_STATUS_DELETE_PENDING (86)
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED (87)
+#define NT_STATUS_UNKNOWN_REVISION (88)
+#define NT_STATUS_REVISION_MISMATCH (89)
+#define NT_STATUS_INVALID_OWNER (90)
+#define NT_STATUS_INVALID_PRIMARY_GROUP (91)
+#define NT_STATUS_NO_IMPERSONATION_TOKEN (92)
+#define NT_STATUS_CANT_DISABLE_MANDATORY (93)
+#define NT_STATUS_NO_LOGON_SERVERS (94)
+#define NT_STATUS_NO_SUCH_LOGON_SESSION (95)
+#define NT_STATUS_NO_SUCH_PRIVILEGE (96)
+#define NT_STATUS_PRIVILEGE_NOT_HELD (97)
+#define NT_STATUS_INVALID_ACCOUNT_NAME (98)
+#define NT_STATUS_USER_EXISTS (99)
+#define NT_STATUS_NO_SUCH_USER (100)
+#define NT_STATUS_GROUP_EXISTS (101)
+#define NT_STATUS_NO_SUCH_GROUP (102)
+#define NT_STATUS_MEMBER_IN_GROUP (103)
+#define NT_STATUS_MEMBER_NOT_IN_GROUP (104)
+#define NT_STATUS_LAST_ADMIN (105)
+#define NT_STATUS_WRONG_PASSWORD (106)
+#define NT_STATUS_ILL_FORMED_PASSWORD (107)
+#define NT_STATUS_PASSWORD_RESTRICTION (108)
+#define NT_STATUS_LOGON_FAILURE (109)
+#define NT_STATUS_ACCOUNT_RESTRICTION (110)
+#define NT_STATUS_INVALID_LOGON_HOURS (111)
+#define NT_STATUS_INVALID_WORKSTATION (112)
+#define NT_STATUS_PASSWORD_EXPIRED (113)
+#define NT_STATUS_ACCOUNT_DISABLED (114)
+#define NT_STATUS_NONE_MAPPED (115)
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED (116)
+#define NT_STATUS_LUIDS_EXHAUSTED (117)
+#define NT_STATUS_INVALID_SUB_AUTHORITY (118)
+#define NT_STATUS_INVALID_ACL (119)
+#define NT_STATUS_INVALID_SID (120)
+#define NT_STATUS_INVALID_SECURITY_DESCR (121)
+#define NT_STATUS_PROCEDURE_NOT_FOUND (122)
+#define NT_STATUS_INVALID_IMAGE_FORMAT (123)
+#define NT_STATUS_NO_TOKEN (124)
+#define NT_STATUS_BAD_INHERITANCE_ACL (125)
+#define NT_STATUS_RANGE_NOT_LOCKED (126)
+#define NT_STATUS_DISK_FULL (127)
+#define NT_STATUS_SERVER_DISABLED (128)
+#define NT_STATUS_SERVER_NOT_DISABLED (129)
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED (130)
+#define NT_STATUS_GUIDS_EXHAUSTED (131)
+#define NT_STATUS_INVALID_ID_AUTHORITY (132)
+#define NT_STATUS_AGENTS_EXHAUSTED (133)
+#define NT_STATUS_INVALID_VOLUME_LABEL (134)
+#define NT_STATUS_SECTION_NOT_EXTENDED (135)
+#define NT_STATUS_NOT_MAPPED_DATA (136)
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND (137)
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND (138)
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND (139)
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED (140)
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND (141)
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO (142)
+#define NT_STATUS_FLOAT_INEXACT_RESULT (143)
+#define NT_STATUS_FLOAT_INVALID_OPERATION (144)
+#define NT_STATUS_FLOAT_OVERFLOW (145)
+#define NT_STATUS_FLOAT_STACK_CHECK (146)
+#define NT_STATUS_FLOAT_UNDERFLOW (147)
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO (148)
+#define NT_STATUS_INTEGER_OVERFLOW (149)
+#define NT_STATUS_PRIVILEGED_INSTRUCTION (150)
+#define NT_STATUS_TOO_MANY_PAGING_FILES (151)
+#define NT_STATUS_FILE_INVALID (152)
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED (153)
+#define NT_STATUS_INSUFFICIENT_RESOURCES (154)
+#define NT_STATUS_DFS_EXIT_PATH_FOUND (155)
+#define NT_STATUS_DEVICE_DATA_ERROR (156)
+#define NT_STATUS_DEVICE_NOT_CONNECTED (157)
+#define NT_STATUS_DEVICE_POWER_FAILURE (158)
+#define NT_STATUS_FREE_VM_NOT_AT_BASE (159)
+#define NT_STATUS_MEMORY_NOT_ALLOCATED (160)
+#define NT_STATUS_WORKING_SET_QUOTA (161)
+#define NT_STATUS_MEDIA_WRITE_PROTECTED (162)
+#define NT_STATUS_DEVICE_NOT_READY (163)
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES (164)
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL (165)
+#define NT_STATUS_CANT_OPEN_ANONYMOUS (166)
+#define NT_STATUS_BAD_VALIDATION_CLASS (167)
+#define NT_STATUS_BAD_TOKEN_TYPE (168)
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD (169)
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT (170)
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE (171)
+#define NT_STATUS_PIPE_NOT_AVAILABLE (172)
+#define NT_STATUS_INVALID_PIPE_STATE (173)
+#define NT_STATUS_PIPE_BUSY (174)
+#define NT_STATUS_ILLEGAL_FUNCTION (175)
+#define NT_STATUS_PIPE_DISCONNECTED (176)
+#define NT_STATUS_PIPE_CLOSING (177)
+#define NT_STATUS_PIPE_CONNECTED (178)
+#define NT_STATUS_PIPE_LISTENING (179)
+#define NT_STATUS_INVALID_READ_MODE (180)
+#define NT_STATUS_IO_TIMEOUT (181)
+#define NT_STATUS_FILE_FORCED_CLOSED (182)
+#define NT_STATUS_PROFILING_NOT_STARTED (183)
+#define NT_STATUS_PROFILING_NOT_STOPPED (184)
+#define NT_STATUS_COULD_NOT_INTERPRET (185)
+#define NT_STATUS_FILE_IS_A_DIRECTORY (186)
+#define NT_STATUS_NOT_SUPPORTED (187)
+#define NT_STATUS_REMOTE_NOT_LISTENING (188)
+#define NT_STATUS_DUPLICATE_NAME (189)
+#define NT_STATUS_BAD_NETWORK_PATH (190)
+#define NT_STATUS_NETWORK_BUSY (191)
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST (192)
+#define NT_STATUS_TOO_MANY_COMMANDS (193)
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR (194)
+#define NT_STATUS_INVALID_NETWORK_RESPONSE (195)
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR (196)
+#define NT_STATUS_BAD_REMOTE_ADAPTER (197)
+#define NT_STATUS_PRINT_QUEUE_FULL (198)
+#define NT_STATUS_NO_SPOOL_SPACE (199)
+#define NT_STATUS_PRINT_CANCELLED (200)
+#define NT_STATUS_NETWORK_NAME_DELETED (201)
+#define NT_STATUS_NETWORK_ACCESS_DENIED (202)
+#define NT_STATUS_BAD_DEVICE_TYPE (203)
+#define NT_STATUS_BAD_NETWORK_NAME (204)
+#define NT_STATUS_TOO_MANY_NAMES (205)
+#define NT_STATUS_TOO_MANY_SESSIONS (206)
+#define NT_STATUS_SHARING_PAUSED (207)
+#define NT_STATUS_REQUEST_NOT_ACCEPTED (208)
+#define NT_STATUS_REDIRECTOR_PAUSED (209)
+#define NT_STATUS_NET_WRITE_FAULT (210)
+#define NT_STATUS_PROFILING_AT_LIMIT (211)
+#define NT_STATUS_NOT_SAME_DEVICE (212)
+#define NT_STATUS_FILE_RENAMED (213)
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED (214)
+#define NT_STATUS_NO_SECURITY_ON_OBJECT (215)
+#define NT_STATUS_CANT_WAIT (216)
+#define NT_STATUS_PIPE_EMPTY (217)
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO (218)
+#define NT_STATUS_CANT_TERMINATE_SELF (219)
+#define NT_STATUS_INVALID_SERVER_STATE (220)
+#define NT_STATUS_INVALID_DOMAIN_STATE (221)
+#define NT_STATUS_INVALID_DOMAIN_ROLE (222)
+#define NT_STATUS_NO_SUCH_DOMAIN (223)
+#define NT_STATUS_DOMAIN_EXISTS (224)
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED (225)
+#define NT_STATUS_OPLOCK_NOT_GRANTED (226)
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL (227)
+#define NT_STATUS_INTERNAL_DB_CORRUPTION (228)
+#define NT_STATUS_INTERNAL_ERROR (229)
+#define NT_STATUS_GENERIC_NOT_MAPPED (230)
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT (231)
+#define NT_STATUS_INVALID_USER_BUFFER (232)
+#define NT_STATUS_UNEXPECTED_IO_ERROR (233)
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR (234)
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR (235)
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR (236)
+#define NT_STATUS_NOT_LOGON_PROCESS (237)
+#define NT_STATUS_LOGON_SESSION_EXISTS (238)
+#define NT_STATUS_INVALID_PARAMETER_1 (239)
+#define NT_STATUS_INVALID_PARAMETER_2 (240)
+#define NT_STATUS_INVALID_PARAMETER_3 (241)
+#define NT_STATUS_INVALID_PARAMETER_4 (242)
+#define NT_STATUS_INVALID_PARAMETER_5 (243)
+#define NT_STATUS_INVALID_PARAMETER_6 (244)
+#define NT_STATUS_INVALID_PARAMETER_7 (245)
+#define NT_STATUS_INVALID_PARAMETER_8 (246)
+#define NT_STATUS_INVALID_PARAMETER_9 (247)
+#define NT_STATUS_INVALID_PARAMETER_10 (248)
+#define NT_STATUS_INVALID_PARAMETER_11 (249)
+#define NT_STATUS_INVALID_PARAMETER_12 (250)
+#define NT_STATUS_REDIRECTOR_NOT_STARTED (251)
+#define NT_STATUS_REDIRECTOR_STARTED (252)
+#define NT_STATUS_STACK_OVERFLOW (253)
+#define NT_STATUS_NO_SUCH_PACKAGE (254)
+#define NT_STATUS_BAD_FUNCTION_TABLE (255)
+#define NT_STATUS_DIRECTORY_NOT_EMPTY (257)
+#define NT_STATUS_FILE_CORRUPT_ERROR (258)
+#define NT_STATUS_NOT_A_DIRECTORY (259)
+#define NT_STATUS_BAD_LOGON_SESSION_STATE (260)
+#define NT_STATUS_LOGON_SESSION_COLLISION (261)
+#define NT_STATUS_NAME_TOO_LONG (262)
+#define NT_STATUS_FILES_OPEN (263)
+#define NT_STATUS_CONNECTION_IN_USE (264)
+#define NT_STATUS_MESSAGE_NOT_FOUND (265)
+#define NT_STATUS_PROCESS_IS_TERMINATING (266)
+#define NT_STATUS_INVALID_LOGON_TYPE (267)
+#define NT_STATUS_NO_GUID_TRANSLATION (268)
+#define NT_STATUS_CANNOT_IMPERSONATE (269)
+#define NT_STATUS_IMAGE_ALREADY_LOADED (270)
+#define NT_STATUS_ABIOS_NOT_PRESENT (271)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST (272)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED (273)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER (274)
+#define NT_STATUS_ABIOS_INVALID_COMMAND (275)
+#define NT_STATUS_ABIOS_INVALID_LID (276)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE (277)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR (278)
+#define NT_STATUS_NO_LDT (279)
+#define NT_STATUS_INVALID_LDT_SIZE (280)
+#define NT_STATUS_INVALID_LDT_OFFSET (281)
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR (282)
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT (283)
+#define NT_STATUS_RXACT_INVALID_STATE (284)
+#define NT_STATUS_RXACT_COMMIT_FAILURE (285)
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO (286)
+#define NT_STATUS_TOO_MANY_OPENED_FILES (287)
+#define NT_STATUS_CANCELLED (288)
+#define NT_STATUS_CANNOT_DELETE (289)
+#define NT_STATUS_INVALID_COMPUTER_NAME (290)
+#define NT_STATUS_FILE_DELETED (291)
+#define NT_STATUS_SPECIAL_ACCOUNT (292)
+#define NT_STATUS_SPECIAL_GROUP (293)
+#define NT_STATUS_SPECIAL_USER (294)
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP (295)
+#define NT_STATUS_FILE_CLOSED (296)
+#define NT_STATUS_TOO_MANY_THREADS (297)
+#define NT_STATUS_THREAD_NOT_IN_PROCESS (298)
+#define NT_STATUS_TOKEN_ALREADY_IN_USE (299)
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED (300)
+#define NT_STATUS_COMMITMENT_LIMIT (301)
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT (302)
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ (303)
+#define NT_STATUS_INVALID_IMAGE_PROTECT (304)
+#define NT_STATUS_INVALID_IMAGE_WIN_16 (305)
+#define NT_STATUS_LOGON_SERVER_CONFLICT (306)
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC (307)
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED (308)
+#define NT_STATUS_DLL_NOT_FOUND (309)
+#define NT_STATUS_OPEN_FAILED (310)
+#define NT_STATUS_IO_PRIVILEGE_FAILED (311)
+#define NT_STATUS_ORDINAL_NOT_FOUND (312)
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND (313)
+#define NT_STATUS_CONTROL_C_EXIT (314)
+#define NT_STATUS_LOCAL_DISCONNECT (315)
+#define NT_STATUS_REMOTE_DISCONNECT (316)
+#define NT_STATUS_REMOTE_RESOURCES (317)
+#define NT_STATUS_LINK_FAILED (318)
+#define NT_STATUS_LINK_TIMEOUT (319)
+#define NT_STATUS_INVALID_CONNECTION (320)
+#define NT_STATUS_INVALID_ADDRESS (321)
+#define NT_STATUS_DLL_INIT_FAILED (322)
+#define NT_STATUS_MISSING_SYSTEMFILE (323)
+#define NT_STATUS_UNHANDLED_EXCEPTION (324)
+#define NT_STATUS_APP_INIT_FAILURE (325)
+#define NT_STATUS_PAGEFILE_CREATE_FAILED (326)
+#define NT_STATUS_NO_PAGEFILE (327)
+#define NT_STATUS_INVALID_LEVEL (328)
+#define NT_STATUS_WRONG_PASSWORD_CORE (329)
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT (330)
+#define NT_STATUS_PIPE_BROKEN (331)
+#define NT_STATUS_REGISTRY_CORRUPT (332)
+#define NT_STATUS_REGISTRY_IO_FAILED (333)
+#define NT_STATUS_NO_EVENT_PAIR (334)
+#define NT_STATUS_UNRECOGNIZED_VOLUME (335)
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED (336)
+#define NT_STATUS_NO_SUCH_ALIAS (337)
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS (338)
+#define NT_STATUS_MEMBER_IN_ALIAS (339)
+#define NT_STATUS_ALIAS_EXISTS (340)
+#define NT_STATUS_LOGON_NOT_GRANTED (341)
+#define NT_STATUS_TOO_MANY_SECRETS (342)
+#define NT_STATUS_SECRET_TOO_LONG (343)
+#define NT_STATUS_INTERNAL_DB_ERROR (344)
+#define NT_STATUS_FULLSCREEN_MODE (345)
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS (346)
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED (347)
+#define NT_STATUS_NOT_REGISTRY_FILE (348)
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED (349)
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR (350)
+#define NT_STATUS_FT_MISSING_MEMBER (351)
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY (352)
+#define NT_STATUS_ILLEGAL_CHARACTER (353)
+#define NT_STATUS_UNMAPPABLE_CHARACTER (354)
+#define NT_STATUS_UNDEFINED_CHARACTER (355)
+#define NT_STATUS_FLOPPY_VOLUME (356)
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND (357)
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER (358)
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR (359)
+#define NT_STATUS_FLOPPY_BAD_REGISTERS (360)
+#define NT_STATUS_DISK_RECALIBRATE_FAILED (361)
+#define NT_STATUS_DISK_OPERATION_FAILED (362)
+#define NT_STATUS_DISK_RESET_FAILED (363)
+#define NT_STATUS_SHARED_IRQ_BUSY (364)
+#define NT_STATUS_FT_ORPHANING (365)
+#define NT_STATUS_PARTITION_FAILURE (370)
+#define NT_STATUS_INVALID_BLOCK_LENGTH (371)
+#define NT_STATUS_DEVICE_NOT_PARTITIONED (372)
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA (373)
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA (374)
+#define NT_STATUS_EOM_OVERFLOW (375)
+#define NT_STATUS_NO_MEDIA (376)
+#define NT_STATUS_NO_SUCH_MEMBER (378)
+#define NT_STATUS_INVALID_MEMBER (379)
+#define NT_STATUS_KEY_DELETED (380)
+#define NT_STATUS_NO_LOG_SPACE (381)
+#define NT_STATUS_TOO_MANY_SIDS (382)
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED (383)
+#define NT_STATUS_KEY_HAS_CHILDREN (384)
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE (385)
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR (386)
+#define NT_STATUS_DRIVER_INTERNAL_ERROR (387)
+#define NT_STATUS_INVALID_DEVICE_STATE (388)
+#define NT_STATUS_IO_DEVICE_ERROR (389)
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR (390)
+#define NT_STATUS_BACKUP_CONTROLLER (391)
+#define NT_STATUS_LOG_FILE_FULL (392)
+#define NT_STATUS_TOO_LATE (393)
+#define NT_STATUS_NO_TRUST_LSA_SECRET (394)
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT (395)
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE (396)
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE (397)
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT (398)
+#define NT_STATUS_EVENTLOG_CANT_START (399)
+#define NT_STATUS_TRUST_FAILURE (400)
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED (401)
+#define NT_STATUS_NETLOGON_NOT_STARTED (402)
+#define NT_STATUS_ACCOUNT_EXPIRED (403)
+#define NT_STATUS_POSSIBLE_DEADLOCK (404)
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT (405)
+#define NT_STATUS_REMOTE_SESSION_LIMIT (406)
+#define NT_STATUS_EVENTLOG_FILE_CHANGED (407)
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT (408)
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT (409)
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT (410)
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT (411)
+#define NT_STATUS_FS_DRIVER_REQUIRED (412)
+#define NT_STATUS_NO_USER_SESSION_KEY (514)
+#define NT_STATUS_USER_SESSION_DELETED (515)
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND (516)
+#define NT_STATUS_INSUFF_SERVER_RESOURCES (517)
+#define NT_STATUS_INVALID_BUFFER_SIZE (518)
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT (519)
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD (520)
+#define NT_STATUS_TOO_MANY_ADDRESSES (521)
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS (522)
+#define NT_STATUS_ADDRESS_CLOSED (523)
+#define NT_STATUS_CONNECTION_DISCONNECTED (524)
+#define NT_STATUS_CONNECTION_RESET (525)
+#define NT_STATUS_TOO_MANY_NODES (526)
+#define NT_STATUS_TRANSACTION_ABORTED (527)
+#define NT_STATUS_TRANSACTION_TIMED_OUT (528)
+#define NT_STATUS_TRANSACTION_NO_RELEASE (529)
+#define NT_STATUS_TRANSACTION_NO_MATCH (530)
+#define NT_STATUS_TRANSACTION_RESPONDED (531)
+#define NT_STATUS_TRANSACTION_INVALID_ID (532)
+#define NT_STATUS_TRANSACTION_INVALID_TYPE (533)
+#define NT_STATUS_NOT_SERVER_SESSION (534)
+#define NT_STATUS_NOT_CLIENT_SESSION (535)
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE (536)
+#define NT_STATUS_DEBUG_ATTACH_FAILED (537)
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED (538)
+#define NT_STATUS_DATA_NOT_ACCEPTED (539)
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND (540)
+#define NT_STATUS_VDM_HARD_ERROR (541)
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT (542)
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH (543)
+#define NT_STATUS_MAPPED_ALIGNMENT (544)
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH (545)
+#define NT_STATUS_LOST_WRITEBEHIND_DATA (546)
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID (547)
+#define NT_STATUS_PASSWORD_MUST_CHANGE (548)
+#define NT_STATUS_NOT_FOUND (549)
+#define NT_STATUS_NOT_TINY_STREAM (550)
+#define NT_STATUS_RECOVERY_FAILURE (551)
+#define NT_STATUS_STACK_OVERFLOW_READ (552)
+#define NT_STATUS_FAIL_CHECK (553)
+#define NT_STATUS_DUPLICATE_OBJECTID (554)
+#define NT_STATUS_OBJECTID_EXISTS (555)
+#define NT_STATUS_CONVERT_TO_LARGE (556)
+#define NT_STATUS_RETRY (557)
+#define NT_STATUS_FOUND_OUT_OF_SCOPE (558)
+#define NT_STATUS_ALLOCATE_BUCKET (559)
+#define NT_STATUS_PROPSET_NOT_FOUND (560)
+#define NT_STATUS_MARSHALL_OVERFLOW (561)
+#define NT_STATUS_INVALID_VARIANT (562)
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND (563)
+#define NT_STATUS_ACCOUNT_LOCKED_OUT (564)
+#define NT_STATUS_HANDLE_NOT_CLOSABLE (565)
+#define NT_STATUS_CONNECTION_REFUSED (566)
+#define NT_STATUS_GRACEFUL_DISCONNECT (567)
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED (568)
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED (569)
+#define NT_STATUS_CONNECTION_INVALID (570)
+#define NT_STATUS_CONNECTION_ACTIVE (571)
+#define NT_STATUS_NETWORK_UNREACHABLE (572)
+#define NT_STATUS_HOST_UNREACHABLE (573)
+#define NT_STATUS_PROTOCOL_UNREACHABLE (574)
+#define NT_STATUS_PORT_UNREACHABLE (575)
+#define NT_STATUS_REQUEST_ABORTED (576)
+#define NT_STATUS_CONNECTION_ABORTED (577)
+#define NT_STATUS_BAD_COMPRESSION_BUFFER (578)
+#define NT_STATUS_USER_MAPPED_FILE (579)
+#define NT_STATUS_AUDIT_FAILED (580)
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET (581)
+#define NT_STATUS_CONNECTION_COUNT_LIMIT (582)
+#define NT_STATUS_LOGIN_TIME_RESTRICTION (583)
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION (584)
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH (585)
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO (592)
+#define NT_STATUS_BAD_DLL_ENTRYPOINT (593)
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT (594)
+#define NT_STATUS_LPC_REPLY_LOST (595)
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 (596)
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 (597)
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT (598)
+#define NT_STATUS_PATH_NOT_COVERED (599)
+#define NT_STATUS_NO_CALLBACK_ACTIVE (600)
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED (601)
+#define NT_STATUS_PWD_TOO_SHORT (602)
+#define NT_STATUS_PWD_TOO_RECENT (603)
+#define NT_STATUS_PWD_HISTORY_CONFLICT (604)
+#define NT_STATUS_PLUGPLAY_NO_DEVICE (606)
+#define NT_STATUS_UNSUPPORTED_COMPRESSION (607)
+#define NT_STATUS_INVALID_HW_PROFILE (608)
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH (609)
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND (610)
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND (611)
+#define NT_STATUS_RESOURCE_NOT_OWNED (612)
+#define NT_STATUS_TOO_MANY_LINKS (613)
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT (614)
+#define NT_STATUS_FILE_IS_OFFLINE (615)
+#define NT_STATUS_NOTIFY_ENUM_DIR (0x10C)
diff --git a/source/include/proto.h b/source/include/proto.h
new file mode 100644
index 00000000000..1c09d627db9
--- /dev/null
+++ b/source/include/proto.h
@@ -0,0 +1,2221 @@
+#ifndef _PROTO_H_
+#define _PROTO_H_
+/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/*The following definitions come from client/client.c */
+
+void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(file_info *),BOOL recurse_dir, BOOL dirstoo);
+char *complete_cmd_null(char *text, int state);
+void complete_process_file(file_info *f);
+char *complete_remote_file(char *text, int state);
+char *complete_cmd(char *text, int state);
+char **completion_fn(char *text, int start, int end);
+
+/*The following definitions come from client/clientutil.c */
+
+void cli_setup_pkt(char *outbuf);
+BOOL cli_call_api(char *pipe_name, int pipe_name_len,
+ int prcnt,int drcnt, int srcnt,
+ int mprcnt,int mdrcnt,
+ int *rprcnt,int *rdrcnt,
+ char *param,char *data, uint16 *setup,
+ char **rparam,char **rdata);
+BOOL cli_receive_trans_response(char *inbuf,int trans,
+ int *data_len,int *param_len,
+ char **data,char **param);
+BOOL cli_send_trans_request(char *outbuf,int trans,
+ char *name,int namelen, int fid,int flags,
+ char *data,char *param,uint16 *setup,
+ int ldata,int lparam,int lsetup,
+ int mdata,int mparam,int msetup);
+BOOL cli_send_session_request(char *inbuf,char *outbuf);
+BOOL cli_send_login(char *inbuf,char *outbuf,BOOL start_session,BOOL use_setup, struct connection_options *options);
+void cli_send_logout(char *dum_in, char *dum_out);
+BOOL cli_open_sockets(int port );
+BOOL cli_reopen_connection(char *inbuf,char *outbuf);
+
+/*The following definitions come from client/clitar.c */
+
+void cmd_block(char *dum_in, char *dum_out);
+void cmd_tarmode(char *dum_in, char *dum_out);
+void cmd_setmode(char *dum_in, char *dum_out);
+void cmd_tar(char *inbuf, char *outbuf);
+int process_tar(char *inbuf, char *outbuf);
+int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+
+/*The following definitions come from lib/access.c */
+
+BOOL allow_access(char *deny_list,char *allow_list,
+ char *cname,char *caddr);
+BOOL check_access(int sock, char *allow_list, char *deny_list);
+
+/*The following definitions come from lib/bitmap.c */
+
+struct bitmap *bitmap_allocate(int n);
+BOOL bitmap_set(struct bitmap *bm, unsigned i);
+BOOL bitmap_clear(struct bitmap *bm, unsigned i);
+int bitmap_find(struct bitmap *bm, unsigned ofs);
+
+/*The following definitions come from lib/charcnv.c */
+
+char *unix2dos_format(char *str,BOOL overwrite);
+char *dos2unix_format(char *str, BOOL overwrite);
+void interpret_character_set(char *str);
+
+/*The following definitions come from lib/charset.c */
+
+void charset_initialise(void);
+void codepage_initialise(int client_codepage);
+void add_char_string(char *s);
+
+/*The following definitions come from lib/debug.c */
+
+void sig_usr2( int sig );
+void sig_usr1( int sig );
+void setup_logging( char *pname, BOOL interactive );
+void reopen_logs( void );
+void force_check_log_size( void );
+void dbgflush( void );
+BOOL dbghdr( int level, char *file, char *func, int line );
+
+/*The following definitions come from lib/fault.c */
+
+void fault_setup(void (*fn)(void *));
+
+/*The following definitions come from lib/genrand.c */
+
+void generate_random_buffer( unsigned char *out, int len, BOOL re_seed);
+
+/*The following definitions come from lib/getsmbpass.c */
+
+char *getsmbpass(char *prompt) ;
+
+/*The following definitions come from lib/interface.c */
+
+void load_interfaces(void);
+void iface_set_default(char *ip,char *bcast,char *nmask);
+BOOL ismyip(struct in_addr ip);
+BOOL is_local_net(struct in_addr from);
+int iface_count(void);
+BOOL we_are_multihomed(void);
+struct interface *get_interface(int n);
+struct in_addr *iface_n_ip(int n);
+unsigned iface_hash(void);
+struct in_addr *iface_bcast(struct in_addr ip);
+struct in_addr *iface_ip(struct in_addr ip);
+
+/*The following definitions come from lib/kanji.c */
+
+void interpret_coding_system(char *str);
+void initialize_multibyte_vectors( int client_codepage);
+
+/*The following definitions come from lib/md4.c */
+
+void mdfour(unsigned char *out, unsigned char *in, int n);
+
+/*The following definitions come from lib/membuffer.c */
+
+void mem_init(struct mem_buf *buf, int margin);
+void mem_create(struct mem_buf *buf, char *data, int size, int margin, BOOL dynamic);
+BOOL mem_alloc_data(struct mem_buf *buf, int size);
+BOOL mem_buf_copy(char *copy_into, struct mem_buf *buf,
+ uint32 offset, uint32 len);
+BOOL mem_buf_init(struct mem_buf **buf, uint32 margin);
+void mem_buf_free(struct mem_buf **buf);
+void mem_free_data(struct mem_buf *buf);
+BOOL mem_realloc_data(struct mem_buf *buf, int new_size);
+BOOL mem_grow_data(struct mem_buf **buf, BOOL io, int new_size, BOOL force_grow);
+uint32 mem_buf_len(struct mem_buf *buf);
+char *mem_data(struct mem_buf **buf, uint32 offset);
+
+/*The following definitions come from lib/netmask.c */
+
+int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask);
+
+/*The following definitions come from lib/pidfile.c */
+
+pid_t pidfile_pid(char *name);
+void pidfile_create(char *name);
+
+/*The following definitions come from lib/replace.c */
+
+char *rep_inet_ntoa(struct in_addr ip);
+
+/*The following definitions come from lib/signal.c */
+
+void BlockSignals(BOOL block,int signum);
+void CatchSignal(int signum,void (*handler)(int ));
+void CatchChild(void);
+
+/*The following definitions come from lib/slprintf.c */
+
+int vslprintf(char *str, int n, char *format, va_list ap);
+
+/*The following definitions come from lib/smbrun.c */
+
+int smbrun(char *cmd,char *outfile,BOOL shared);
+
+/*The following definitions come from lib/system.c */
+
+int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
+int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
+int sys_stat(char *fname,SMB_STRUCT_STAT *sbuf);
+int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf);
+int sys_lstat(char *fname,SMB_STRUCT_STAT *sbuf);
+int sys_ftruncate(int fd, SMB_OFF_T offset);
+SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence);
+int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence);
+SMB_OFF_T sys_ftell(FILE *fp);
+int dos_unlink(char *fname);
+int dos_open(char *fname,int flags,mode_t mode);
+DIR *dos_opendir(char *dname);
+int dos_stat(char *fname,SMB_STRUCT_STAT *sbuf);
+int sys_waitpid(pid_t pid,int *status,int options);
+int dos_lstat(char *fname,SMB_STRUCT_STAT *sbuf);
+int dos_mkdir(char *dname,mode_t mode);
+int dos_rmdir(char *dname);
+int dos_chdir(char *dname);
+int dos_utime(char *fname,struct utimbuf *times);
+int dos_rename(char *from, char *to);
+int dos_chmod(char *fname,mode_t mode);
+char *dos_getwd(char *s);
+int sys_chown(char *fname,int uid,int gid);
+int sys_chroot(char *dname);
+struct hostent *sys_gethostbyname(char *name);
+BOOL set_process_capability( uint32 cap_flag, BOOL enable );
+BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable );
+long sys_random(void);
+void sys_srandom(unsigned int seed);
+
+/*The following definitions come from lib/time.c */
+
+void GetTimeOfDay(struct timeval *tval);
+void TimeInit(void);
+int TimeDiff(time_t t);
+struct tm *LocalTime(time_t *t);
+time_t interpret_nt_time(NTTIME *t);
+time_t interpret_long_date(char *p);
+void put_long_date(char *p,time_t t);
+BOOL null_mtime(time_t mtime);
+void put_dos_date(char *buf,int offset,time_t unixdate);
+void put_dos_date2(char *buf,int offset,time_t unixdate);
+void put_dos_date3(char *buf,int offset,time_t unixdate);
+time_t make_unix_date(void *date_ptr);
+time_t make_unix_date2(void *date_ptr);
+time_t make_unix_date3(void *date_ptr);
+char *http_timestring(time_t t);
+char *timestring(void );
+time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs);
+
+/*The following definitions come from lib/ufc.c */
+
+char *ufc_crypt(char *key,char *salt);
+
+/*The following definitions come from lib/username.c */
+
+char *get_home_dir(char *user);
+BOOL map_username(char *user);
+struct passwd *Get_Pwnam(char *user,BOOL allow_change);
+BOOL user_in_list(char *user,char *list);
+
+/*The following definitions come from lib/util.c */
+
+char *tmpdir(void);
+BOOL is_a_socket(int fd);
+BOOL next_token(char **ptr,char *buff,char *sep, int bufsize);
+char **toktocliplist(int *ctok, char *sep);
+void set_socket_options(int fd, char *options);
+void close_sockets(void );
+BOOL in_group(gid_t group, int current_gid, int ngroups, GID_T *groups);
+char *StrCpy(char *dest,char *src);
+char *StrnCpy(char *dest,char *src,int n);
+void putip(void *dest,void *src);
+char *dns_to_netbios_name(char *dns_name);
+int name_mangle( char *In, char *Out, char name_type );
+BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf);
+time_t file_modtime(char *fname);
+BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st);
+SMB_OFF_T file_size(char *file_name);
+char *attrib_string(int mode);
+int StrCaseCmp(char *s, char *t);
+int StrnCaseCmp(char *s, char *t, int n);
+BOOL strequal(char *s1, char *s2);
+BOOL strnequal(char *s1,char *s2,int n);
+BOOL strcsequal(char *s1,char *s2);
+void strlower(char *s);
+void strupper(char *s);
+void strnorm(char *s);
+BOOL strisnormal(char *s);
+void string_replace(char *s,char oldc,char newc);
+void unix_format(char *fname);
+void dos_format(char *fname);
+void show_msg(char *buf);
+int smb_len(char *buf);
+void _smb_setlen(char *buf,int len);
+void smb_setlen(char *buf,int len);
+int set_message(char *buf,int num_words,int num_bytes,BOOL zero);
+int smb_buflen(char *buf);
+char *smb_buf(char *buf);
+int smb_offset(char *p,char *buf);
+char *skip_string(char *buf,int n);
+BOOL trim_string(char *s,char *front,char *back);
+void dos_clean_name(char *s);
+void unix_clean_name(char *s);
+int ChDir(char *path);
+char *GetWd(char *str);
+BOOL reduce_name(char *s,char *dir,BOOL widelinks);
+void expand_mask(char *Mask,BOOL doext);
+BOOL strhasupper(char *s);
+BOOL strhaslower(char *s);
+int count_chars(char *s,char c);
+void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date);
+void close_low_fds(void);
+ssize_t write_socket(int fd,char *buf,size_t len);
+ssize_t read_udp_socket(int fd,char *buf,size_t len);
+ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out);
+int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew);
+BOOL send_keepalive(int client);
+ssize_t read_data(int fd,char *buffer,size_t N);
+ssize_t write_data(int fd,char *buffer,size_t N);
+SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n,char *header,int headlen,int align);
+ssize_t read_smb_length(int fd,char *inbuf,unsigned int timeout);
+BOOL receive_smb(int fd,char *buffer, unsigned int timeout);
+BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout);
+BOOL send_smb(int fd,char *buffer);
+int name_extract(char *buf,int ofs,char *name);
+int name_len( char *s );
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type);
+BOOL in_list(char *s,char *list,BOOL casesensitive);
+BOOL string_init(char **dest,char *src);
+void string_free(char **s);
+BOOL string_set(char **dest,char *src);
+BOOL string_sub(char *s,char *pattern,char *insert);
+BOOL do_match(char *str, char *regexp, int case_sig);
+BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
+void become_daemon(void);
+BOOL yesno(char *p);
+char *fgets_slash(char *s2,int maxlen,FILE *f);
+int set_filelen(int fd, SMB_OFF_T len);
+void *Realloc(void *p,size_t size);
+BOOL get_myname(char *my_name,struct in_addr *ip);
+BOOL ip_equal(struct in_addr ip1,struct in_addr ip2);
+int open_socket_in(int type, int port, int dlevel,uint32 socket_addr);
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout);
+int interpret_protocol(char *str,int def);
+uint32 interpret_addr(char *str);
+struct in_addr *interpret_addr2(char *str);
+BOOL zero_ip(struct in_addr ip);
+void reset_globals_after_fork(void);
+char *client_name(int fd);
+char *client_addr(int fd);
+void standard_sub_basic(char *str);
+void standard_sub(connection_struct *conn,char *str);
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
+int PutUniCode(char *dst,char *src);
+struct hostent *Get_Hostbyname(char *name);
+BOOL process_exists(int pid);
+char *uidtoname(int uid);
+char *gidtoname(int gid);
+void smb_panic(char *why);
+char *readdirname(void *p);
+BOOL is_in_path(char *name, name_compare_entry *namelist);
+void set_namearray(name_compare_entry **ppname_array, char *namelist);
+void free_namearray(name_compare_entry *name_array);
+BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+BOOL is_myname(char *s);
+void set_remote_arch(enum remote_arch_types type);
+enum remote_arch_types get_remote_arch(void);
+char *skip_unicode_string(char *buf,int n);
+char *unistrn2(uint16 *buf, int len);
+char *unistr2(uint16 *buf);
+int struni2(uint16 *p, char *buf);
+char *unistr(char *buf);
+int unistrcpy(char *dst, char *src);
+char *safe_strcpy(char *dest, char *src, int maxlength);
+char *safe_strcat(char *dest, char *src, int maxlength);
+char *align2(char *q, char *base);
+void print_asc(int level, unsigned char *buf,int len);
+void dump_data(int level,char *buf1,int len);
+char *tab_depth(int depth);
+char *sid_to_string(pstring sidstr_out, DOM_SID *sid);
+BOOL string_to_sid(DOM_SID *sidout, char *sidstr);
+int str_checksum(char *s);
+void zero_free(void *p, size_t size);
+
+/*The following definitions come from libsmb/clientgen.c */
+
+char *cli_errstr(struct cli_state *cli);
+BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
+ 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);
+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);
+BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation);
+BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(char *, uint32, char *));
+BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(char *, uint32, char *));
+BOOL cli_session_setup(struct cli_state *cli,
+ char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup);
+BOOL cli_ulogoff(struct cli_state *cli);
+BOOL cli_send_tconX(struct cli_state *cli,
+ char *share, char *dev, char *pass, int passlen);
+BOOL cli_tdis(struct cli_state *cli);
+BOOL cli_mv(struct cli_state *cli, char *fname_src, char *fname_dst);
+BOOL cli_unlink(struct cli_state *cli, char *fname);
+BOOL cli_mkdir(struct cli_state *cli, char *dname);
+BOOL cli_rmdir(struct cli_state *cli, char *dname);
+int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode);
+BOOL cli_close(struct cli_state *cli, int fnum);
+BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout);
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout);
+int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size);
+int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size);
+BOOL cli_getatr(struct cli_state *cli, char *fname,
+ int *attr, uint32 *size, time_t *t);
+BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t);
+BOOL cli_qpathinfo(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size);
+BOOL cli_qpathinfo2(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, uint32 *size);
+BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size);
+BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
+ char *old_password);
+BOOL cli_negprot(struct cli_state *cli);
+BOOL cli_session_request(struct cli_state *cli,
+ struct nmb_name *calling, struct nmb_name *called);
+BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip);
+BOOL cli_initialise(struct cli_state *cli);
+void cli_shutdown(struct cli_state *cli);
+void cli_error(struct cli_state *cli, int *eclass, int *num);
+void cli_sockopt(struct cli_state *cli, char *options);
+int cli_setpid(struct cli_state *cli, int pid);
+BOOL cli_reestablish_connection(struct cli_state *cli);
+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);
+
+/*The following definitions come from libsmb/credentials.c */
+
+char *credstr(uchar *cred);
+void cred_session_key(DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, char *pass,
+ uchar session_key[8]);
+void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred);
+int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred,
+ UTIME timestamp);
+BOOL clnt_deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred);
+BOOL deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred,
+ DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred);
+
+/*The following definitions come from libsmb/namequery.c */
+
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)(struct packet_struct *));
+struct in_addr *name_query(int fd,char *name,int name_type, BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *));
+FILE *startlmhosts(char *fname);
+BOOL getlmhostsent( FILE *fp, char *name, int *name_type, struct in_addr *ipaddr);
+void endlmhosts(FILE *fp);
+BOOL resolve_name(char *name, struct in_addr *return_ip);
+
+/*The following definitions come from libsmb/nmblib.c */
+
+void debug_nmb_packet(struct packet_struct *p);
+char *namestr(struct nmb_name *n);
+struct packet_struct *copy_packet(struct packet_struct *packet);
+void free_packet(struct packet_struct *packet);
+struct packet_struct *read_packet(int fd,enum packet_type packet_type);
+void make_nmb_name( struct nmb_name *n, char *name, int type, char *this_scope );
+BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2);
+BOOL send_packet(struct packet_struct *p);
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
+void sort_query_replies(char *data, int n, struct in_addr ip);
+
+/*The following definitions come from libsmb/nterr.c */
+
+char *get_nt_error_msg(uint32 nt_code);
+
+/*The following definitions come from libsmb/pwd_cache.c */
+
+void pwd_init(struct pwd_info *pwd);
+void pwd_obfuscate_key(struct pwd_info *pwd, uint32 int_key, char *str_key);
+void pwd_read(struct pwd_info *pwd, char *passwd_report, BOOL do_encrypt);
+void pwd_set_nullpwd(struct pwd_info *pwd);
+void pwd_set_cleartext(struct pwd_info *pwd, char *clr);
+void pwd_get_cleartext(struct pwd_info *pwd, char *clr);
+void pwd_set_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16]);
+void pwd_get_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16]);
+void pwd_make_lm_nt_16(struct pwd_info *pwd, char *clr);
+void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8]);
+void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24]);
+
+/*The following definitions come from libsmb/smbdes.c */
+
+void E_P16(unsigned char *p14,unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
+void E_old_pw_hash( unsigned char *p14, unsigned char *in, unsigned char *out);
+void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key);
+void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key);
+void cred_hash3(unsigned char *out,unsigned char *in,unsigned char *key, int forw);
+void SamOEMhash( unsigned char *data, unsigned char *key, int val);
+
+/*The following definitions come from libsmb/smbencrypt.c */
+
+void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24);
+void E_md4hash(uchar *passwd, uchar *p16);
+void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16]);
+void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]);
+void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24);
+
+/*The following definitions come from libsmb/smberr.c */
+
+char *smb_errstr(char *inbuf);
+
+/*The following definitions come from locking/locking.c */
+
+BOOL is_locked(files_struct *fsp,connection_struct *conn,
+ SMB_OFF_T count,SMB_OFF_T offset, int lock_type);
+BOOL do_lock(files_struct *fsp,connection_struct *conn,
+ SMB_OFF_T count,SMB_OFF_T offset,int lock_type,
+ int *eclass,uint32 *ecode);
+BOOL do_unlock(files_struct *fsp,connection_struct *conn,
+ SMB_OFF_T count,SMB_OFF_T offset,int *eclass,uint32 *ecode);
+BOOL locking_init(int read_only);
+BOOL locking_end(void);
+BOOL lock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int *ptok);
+BOOL unlock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int token);
+int get_share_modes(connection_struct *conn,
+ int token, SMB_DEV_T dev, SMB_INO_T inode,
+ share_mode_entry **shares);
+void del_share_mode(int token, files_struct *fsp);
+BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type);
+BOOL remove_share_oplock(files_struct *fsp, int token);
+int share_mode_forall(void (*fn)(share_mode_entry *, char *));
+void share_status(FILE *f);
+
+/*The following definitions come from locking/locking_shm.c */
+
+struct share_ops *locking_shm_init(int ronly);
+
+/*The following definitions come from locking/locking_slow.c */
+
+struct share_ops *locking_slow_init(int ronly);
+
+/*The following definitions come from locking/shmem.c */
+
+struct shmem_ops *smb_shm_open(int ronly);
+
+/*The following definitions come from locking/shmem_sysv.c */
+
+struct shmem_ops *sysv_shm_open(int ronly);
+
+/*The following definitions come from nmbd/asyncdns.c */
+
+int asyncdns_fd(void);
+void kill_async_dns_child(void);
+void start_async_dns(void);
+void run_dns_queue(void);
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n);
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n);
+void kill_async_dns_child(void);
+
+/*The following definitions come from nmbd/nmbd.c */
+
+BOOL reload_services(BOOL test);
+
+/*The following definitions come from nmbd/nmbd_become_dmb.c */
+
+void add_domain_names(time_t t);
+
+/*The following definitions come from nmbd/nmbd_become_lmb.c */
+
+void insert_permanent_name_into_unicast( struct subnet_record *subrec,
+ struct nmb_name *nmbname, uint16 nb_type );
+void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
+ BOOL force_new_election);
+void become_local_master_browser(struct subnet_record *subrec, struct work_record *work);
+void set_workgroup_local_master_browser_name( struct work_record *work, char *newname);
+
+/*The following definitions come from nmbd/nmbd_browserdb.c */
+
+void update_browser_death_time( struct browse_cache_record *browc );
+struct browse_cache_record *create_browser_in_lmb_cache( char *work_name,
+ char *browser_name,
+ struct in_addr ip );
+struct browse_cache_record *find_browser_in_lmb_cache( char *browser_name );
+void expire_lmb_browsers( time_t t );
+
+/*The following definitions come from nmbd/nmbd_browsesync.c */
+
+void dmb_expire_and_sync_browser_lists(time_t t);
+void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
+ struct work_record *work);
+void collect_all_workgroup_names_from_wins_server(time_t t);
+void sync_all_dmbs(time_t t);
+
+/*The following definitions come from nmbd/nmbd_elections.c */
+
+void check_master_browser_exists(time_t t);
+void run_elections(time_t t);
+void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+BOOL check_elections(void);
+
+/*The following definitions come from nmbd/nmbd_incomingdgrams.c */
+
+void tell_become_backup(void);
+void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_master_browser_announce(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf);
+void process_lm_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_get_backup_list_request(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf);
+void process_reset_browser(struct subnet_record *subrec,
+ struct packet_struct *p,char *buf);
+void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+void process_lm_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf);
+
+/*The following definitions come from nmbd/nmbd_incomingrequests.c */
+
+void process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p);
+void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p);
+
+/*The following definitions come from nmbd/nmbd_lmhosts.c */
+
+void load_lmhosts_file(char *fname);
+BOOL find_name_in_lmhosts(struct nmb_name *nmbname, struct name_record **namerecp);
+
+/*The following definitions come from nmbd/nmbd_logonnames.c */
+
+void add_logon_names(void);
+
+/*The following definitions come from nmbd/nmbd_mynames.c */
+
+BOOL register_my_workgroup_and_names(void);
+void release_my_names(void);
+void refresh_my_names(time_t t);
+
+/*The following definitions come from nmbd/nmbd_namelistdb.c */
+
+void set_samba_nb_type(void);
+void remove_name_from_namelist( struct subnet_record *subrec,
+ struct name_record *namerec );
+struct name_record *find_name_on_subnet( struct subnet_record *subrec,
+ struct nmb_name *nmbname,
+ BOOL self_only );
+struct name_record *find_name_for_remote_broadcast_subnet(
+ struct nmb_name *nmbname,
+ BOOL self_only );
+void update_name_ttl( struct name_record *namerec, int ttl );
+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);
+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);
+void standard_fail_register( struct subnet_record *subrec,
+ struct response_record *rrec,
+ struct nmb_name *nmbname );
+BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip );
+void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip );
+void remove_ip_from_name_record( struct name_record *namerec,
+ struct in_addr remove_ip );
+void standard_success_release( struct subnet_record *subrec,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ struct in_addr released_ip );
+void expire_names_on_subnet(struct subnet_record *subrec, time_t t);
+void expire_names(time_t t);
+void add_samba_names_to_subnet( struct subnet_record *subrec );
+void dump_all_namelists(void);
+
+/*The following definitions come from nmbd/nmbd_namequery.c */
+
+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);
+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);
+
+/*The following definitions come from nmbd/nmbd_nameregister.c */
+
+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);
+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);
+
+/*The following definitions come from nmbd/nmbd_namerelease.c */
+
+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);
+
+/*The following definitions come from nmbd/nmbd_nodestatus.c */
+
+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);
+
+/*The following definitions come from nmbd/nmbd_packets.c */
+
+uint16 get_nb_flags(char *buf);
+void set_nb_flags(char *buf, uint16 nb_flags);
+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 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 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 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 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 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 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);
+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);
+void run_packet_queue(void);
+void retransmit_or_expire_response_records(time_t t);
+BOOL listen_for_packets(BOOL run_election);
+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);
+
+/*The following definitions come from nmbd/nmbd_processlogon.c */
+
+void process_logon_packet(struct packet_struct *p,char *buf,int len,
+ char *mailslot);
+
+/*The following definitions come from nmbd/nmbd_responserecordsdb.c */
+
+void remove_response_record(struct subnet_record *subrec,
+ struct response_record *rrec);
+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 *find_response_record(struct subnet_record **ppsubrec,
+ uint16 id);
+BOOL is_refresh_already_queued(struct subnet_record *subrec, struct name_record *namerec);
+
+/*The following definitions come from nmbd/nmbd_sendannounce.c */
+
+void send_browser_reset(int reset_type, char *to_name, int to_type, struct in_addr to_ip);
+void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work);
+void announce_my_server_names(time_t t);
+void announce_my_lm_server_names(time_t t);
+void reset_announce_timer(void);
+void announce_myself_to_domain_master_browser(time_t t);
+void announce_my_servers_removed(void);
+void announce_remote(time_t t);
+void browse_sync_remote(time_t t);
+
+/*The following definitions come from nmbd/nmbd_serverlistdb.c */
+
+void remove_all_servers(struct work_record *work);
+struct server_record *find_server_in_workgroup(struct work_record *work, char *name);
+void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec);
+struct server_record *create_server_on_workgroup(struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment);
+void update_server_ttl(struct server_record *servrec, int ttl);
+void expire_servers(struct work_record *work, time_t t);
+void write_browse_list(time_t t, BOOL force_write);
+
+/*The following definitions come from nmbd/nmbd_subnetdb.c */
+
+BOOL create_subnets(void);
+BOOL we_are_a_wins_client(void);
+struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec);
+struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec);
+
+/*The following definitions come from nmbd/nmbd_synclists.c */
+
+void sync_browse_lists(struct work_record *work,
+ char *name, int nm_type,
+ struct in_addr ip, BOOL local, BOOL servers);
+void sync_check_completion(void);
+
+/*The following definitions come from nmbd/nmbd_winsproxy.c */
+
+void make_wins_proxy_name_query_request( struct subnet_record *subrec,
+ struct packet_struct *incoming_packet,
+ struct nmb_name *question_name);
+
+/*The following definitions come from nmbd/nmbd_winsserver.c */
+
+BOOL packet_is_for_wins_server(struct packet_struct *packet);
+BOOL initialise_wins(void);
+void wins_process_name_refresh_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void wins_process_name_registration_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
+ struct packet_struct *p);
+void send_wins_name_query_response(int rcode, struct packet_struct *p,
+ struct name_record *namerec);
+void wins_process_name_query_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void wins_process_name_release_request(struct subnet_record *subrec,
+ struct packet_struct *p);
+void initiate_wins_processing(time_t t);
+void wins_write_database(BOOL background);
+
+/*The following definitions come from nmbd/nmbd_workgroupdb.c */
+
+struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
+ fstring name);
+struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
+ fstring name, int ttl);
+void update_workgroup_ttl(struct work_record *work, int ttl);
+void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work);
+void dump_workgroups(BOOL force_write);
+void expire_workgroups_and_servers(time_t t);
+
+/*The following definitions come from param/loadparm.c */
+
+char *lp_logfile(void);
+char *lp_smbrun(void);
+char *lp_configfile(void);
+char *lp_smb_passwd_file(void);
+char *lp_serverstring(void);
+char *lp_printcapname(void);
+char *lp_lockdir(void);
+char *lp_rootdir(void);
+char *lp_defaultservice(void);
+char *lp_msg_command(void);
+char *lp_hosts_equiv(void);
+char *lp_auto_services(void);
+char *lp_passwd_program(void);
+char *lp_passwd_chat(void);
+char *lp_passwordserver(void);
+char *lp_name_resolve_order(void);
+char *lp_workgroup(void);
+char *lp_username_map(void);
+char *lp_groupname_map(void);
+char *lp_logon_script(void);
+char *lp_logon_path(void);
+char *lp_logon_drive(void);
+char *lp_logon_home(void);
+char *lp_remote_announce(void);
+char *lp_remote_browse_sync(void);
+char *lp_wins_server(void);
+char *lp_interfaces(void);
+char *lp_socket_address(void);
+char *lp_nis_home_map_name(void);
+char *lp_netbios_aliases(void);
+char *lp_driverfile(void);
+char *lp_panic_action(void);
+char *lp_domain_sid(void);
+char *lp_domain_groups(void);
+char *lp_domain_admin_group(void);
+char *lp_domain_guest_group(void);
+char *lp_domain_admin_users(void);
+char *lp_domain_guest_users(void);
+char *lp_ldap_server(void);
+char *lp_ldap_suffix(void);
+char *lp_ldap_filter(void);
+char *lp_ldap_root(void);
+char *lp_ldap_rootpasswd(void);
+int lp_ssl_version(void);
+char *lp_ssl_hosts(void);
+char *lp_ssl_hosts_resign(void);
+char *lp_ssl_cacertdir(void);
+char *lp_ssl_cacertfile(void);
+char *lp_ssl_cert(void);
+char *lp_ssl_privkey(void);
+char *lp_ssl_client_cert(void);
+char *lp_ssl_client_privkey(void);
+char *lp_ssl_ciphers(void);
+BOOL lp_ssl_enabled(void);
+BOOL lp_ssl_reqClientCert(void);
+BOOL lp_ssl_reqServerCert(void);
+BOOL lp_ssl_compatibility(void);
+BOOL lp_dns_proxy(void);
+BOOL lp_wins_support(void);
+BOOL lp_we_are_a_wins_server(void);
+BOOL lp_wins_proxy(void);
+BOOL lp_local_master(void);
+BOOL lp_domain_controller(void);
+BOOL lp_domain_master(void);
+BOOL lp_domain_logons(void);
+BOOL lp_preferred_master(void);
+BOOL lp_load_printers(void);
+BOOL lp_use_rhosts(void);
+BOOL lp_readprediction(void);
+BOOL lp_readbmpx(void);
+BOOL lp_readraw(void);
+BOOL lp_writeraw(void);
+BOOL lp_null_passwords(void);
+BOOL lp_strip_dot(void);
+BOOL lp_encrypted_passwords(void);
+BOOL lp_update_encrypted(void);
+BOOL lp_syslog_only(void);
+BOOL lp_timestamp_logs(void);
+BOOL lp_browse_list(void);
+BOOL lp_unix_realname(void);
+BOOL lp_nis_home_map(void);
+BOOL lp_bind_interfaces_only(void);
+BOOL lp_net_wksta_user_logon(void);
+BOOL lp_unix_password_sync(void);
+BOOL lp_passwd_chat_debug(void);
+BOOL lp_ole_locking_compat(void);
+BOOL lp_nt_smb_support(void);
+BOOL lp_stat_cache(void);
+BOOL lp_kernel_oplocks(void);
+int lp_os_level(void);
+int lp_max_ttl(void);
+int lp_max_wins_ttl(void);
+int lp_min_wins_ttl(void);
+int lp_max_log_size(void);
+int lp_maxxmit(void);
+int lp_maxmux(void);
+int lp_passwordlevel(void);
+int lp_usernamelevel(void);
+int lp_readsize(void);
+int lp_shmem_size(void);
+int lp_deadtime(void);
+int lp_maxprotocol(void);
+int lp_security(void);
+int lp_maxdisksize(void);
+int lp_lpqcachetime(void);
+int lp_syslog(void);
+int lp_client_code_page(void);
+int lp_lm_announce(void);
+int lp_lm_interval(void);
+int lp_machine_password_timeout(void);
+int lp_change_notify_timeout(void);
+int lp_stat_cache_size(void);
+int lp_ldap_port(void);
+char *lp_preexec(int );
+char *lp_postexec(int );
+char *lp_rootpreexec(int );
+char *lp_rootpostexec(int );
+char *lp_servicename(int );
+char *lp_pathname(int );
+char *lp_dontdescend(int );
+char *lp_username(int );
+char *lp_guestaccount(int );
+char *lp_invalid_users(int );
+char *lp_valid_users(int );
+char *lp_admin_users(int );
+char *lp_printcommand(int );
+char *lp_lpqcommand(int );
+char *lp_lprmcommand(int );
+char *lp_lppausecommand(int );
+char *lp_lpresumecommand(int );
+char *lp_queuepausecommand(int );
+char *lp_queueresumecommand(int );
+char *lp_printername(int );
+char *lp_printerdriver(int );
+char *lp_hostsallow(int );
+char *lp_hostsdeny(int );
+char *lp_magicscript(int );
+char *lp_magicoutput(int );
+char *lp_comment(int );
+char *lp_force_user(int );
+char *lp_force_group(int );
+char *lp_readlist(int );
+char *lp_writelist(int );
+char *lp_fstype(int );
+char *lp_mangled_map(int );
+char *lp_veto_files(int );
+char *lp_hide_files(int );
+char *lp_veto_oplocks(int );
+char *lp_driverlocation(int );
+BOOL lp_revalidate(int );
+BOOL lp_casesensitive(int );
+BOOL lp_preservecase(int );
+BOOL lp_shortpreservecase(int );
+BOOL lp_casemangle(int );
+BOOL lp_status(int );
+BOOL lp_hide_dot_files(int );
+BOOL lp_browseable(int );
+BOOL lp_readonly(int );
+BOOL lp_no_set_dir(int );
+BOOL lp_guest_ok(int );
+BOOL lp_guest_only(int );
+BOOL lp_print_ok(int );
+BOOL lp_postscript(int );
+BOOL lp_map_hidden(int );
+BOOL lp_map_archive(int );
+BOOL lp_locking(int );
+BOOL lp_strict_locking(int );
+BOOL lp_share_modes(int );
+BOOL lp_oplocks(int );
+BOOL lp_onlyuser(int );
+BOOL lp_manglednames(int );
+BOOL lp_widelinks(int );
+BOOL lp_symlinks(int );
+BOOL lp_syncalways(int );
+BOOL lp_strict_sync(int );
+BOOL lp_map_system(int );
+BOOL lp_delete_readonly(int );
+BOOL lp_fake_oplocks(int );
+BOOL lp_recursive_veto_delete(int );
+BOOL lp_dos_filetimes(int );
+BOOL lp_dos_filetime_resolution(int );
+BOOL lp_fake_dir_create_times(int );
+BOOL lp_blocking_locks(int );
+int lp_create_mode(int );
+int lp_force_create_mode(int );
+int lp_dir_mode(int );
+int lp_force_dir_mode(int );
+int lp_max_connections(int );
+int lp_defaultcase(int );
+int lp_minprintspace(int );
+int lp_printing(int );
+char lp_magicchar(int );
+BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir);
+int lp_add_service(char *pszService, int iDefaultService);
+BOOL lp_add_printer(char *pszPrintername, int iDefaultService);
+BOOL lp_file_list_changed(void);
+void *lp_local_ptr(int snum, void *ptr);
+BOOL lp_do_parameter(int snum, char *pszParmName, char *pszParmValue);
+BOOL lp_is_default(int snum, struct parm_struct *parm);
+struct parm_struct *lp_next_parameter(int snum, int *i, int allparameters);
+BOOL lp_snum_ok(int iService);
+void lp_add_one_printer(char *name,char *comment);
+BOOL lp_loaded(void);
+void lp_killunused(BOOL (*snumused)(int ));
+BOOL lp_load(char *pszFname,BOOL global_only, BOOL save_defaults, BOOL add_ipc);
+int lp_numservices(void);
+void lp_dump(FILE *f, BOOL show_defaults);
+int lp_servicenumber(char *pszServiceName);
+char *volume_label(int snum);
+void lp_remove_service(int snum);
+void lp_copy_service(int snum, char *new_name);
+int lp_default_server_announce(void);
+int lp_major_announce_version(void);
+int lp_minor_announce_version(void);
+void lp_set_name_resolve_order(char *new_order);
+void lp_set_kernel_oplocks(BOOL val);
+
+/*The following definitions come from param/params.c */
+
+BOOL pm_process( char *FileName,
+ BOOL (*sfunc)(char *),
+ BOOL (*pfunc)(char *, char *) );
+
+/*The following definitions come from passdb/ldap.c */
+
+struct passdb_ops *ldap_initialize_password_db(void);
+
+/*The following definitions come from passdb/nispass.c */
+
+struct passdb_ops *nisplus_initialize_password_db(void);
+
+/*The following definitions come from passdb/pass_check.c */
+
+void dfs_unlogin(void);
+BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
+ BOOL (*fn)(char *, char *));
+
+/*The following definitions come from passdb/passdb.c */
+
+BOOL initialize_password_db(void);
+struct smb_passwd *iterate_getsmbpwuid(uid_t smb_userid);
+struct smb_passwd *iterate_getsmbpwnam(char *name);
+void *startsmbpwent(BOOL update);
+void endsmbpwent(void *vp);
+struct smb_passwd *getsmbpwent(void *vp);
+BOOL add_smbpwd_entry(struct smb_passwd *newpwd);
+BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override);
+struct smb_passwd *getsmbpwnam(char *name);
+struct smb_passwd *getsmbpwuid(uid_t smb_userid);
+struct sam_passwd *iterate_getsam21pwnam(char *name);
+struct sam_passwd *iterate_getsam21pwrid(uint32 rid);
+struct sam_passwd *iterate_getsam21pwuid(uid_t uid);
+struct sam_disp_info *getsamdisprid(uint32 rid);
+struct sam_passwd *getsam21pwent(void *vp);
+struct sam_passwd *getsam21pwnam(char *name);
+struct sam_passwd *getsam21pwrid(uint32 rid);
+void pdb_init_smb(struct smb_passwd *user);
+void pdb_init_sam(struct sam_passwd *user);
+struct sam_disp_info *pdb_sam_to_dispinfo(struct sam_passwd *user);
+struct smb_passwd *pdb_sam_to_smb(struct sam_passwd *user);
+char *pdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length);
+uint16 pdb_decode_acct_ctrl(char *p);
+BOOL pdb_gethexpwd(char *p, char *pwd);
+BOOL pdb_name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid);
+BOOL pdb_generate_machine_sid(void);
+uint32 pdb_uid_to_user_rid(uid_t uid);
+uint32 pdb_gid_to_group_rid(gid_t gid);
+BOOL pdb_rid_is_user(uint32 rid);
+
+/*The following definitions come from passdb/smbpass.c */
+
+struct passdb_ops *file_initialize_password_db(void);
+
+/*The following definitions come from passdb/smbpassfile.c */
+
+BOOL do_file_lock(int fd, int waitsecs, int type);
+BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth);
+BOOL pw_file_unlock(int fd, int *plock_depth);
+BOOL trust_password_lock( char *domain, char *name, BOOL update);
+BOOL trust_password_unlock(void);
+BOOL trust_password_delete( char *domain, char *name );
+BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time);
+BOOL set_trust_account_password( unsigned char *md4_new_pwd);
+
+/*The following definitions come from printing/pcap.c */
+
+BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
+void pcap_printer_fn(void (*fn)(char *, char *));
+
+/*The following definitions come from printing/print_svid.c */
+
+void sysv_printer_fn(void (*fn)(char *, char *));
+int sysv_printername_ok(char *name);
+
+/*The following definitions come from printing/printing.c */
+
+void lpq_reset(int snum);
+void print_file(connection_struct *conn, files_struct *file);
+int get_printqueue(int snum,
+ connection_struct *conn,print_queue_struct **queue,
+ print_status_struct *status);
+void del_printqueue(connection_struct *conn,int snum,int jobid);
+void status_printjob(connection_struct *conn,int snum,int jobid,int status);
+int printjob_encode(int snum, int job);
+void printjob_decode(int jobid, int *snum, int *job);
+void status_printqueue(connection_struct *conn,int snum,int status);
+void load_printers(void);
+
+/*The following definitions come from rpc_client/cli_login.c */
+
+BOOL cli_nt_setup_creds(struct cli_state *cli, unsigned char mach_pwd[16]);
+BOOL cli_nt_srv_pwset(struct cli_state *cli, unsigned char *new_hashof_mach_pwd);
+BOOL 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);
+BOOL cli_nt_login_network(struct cli_state *cli, char *domain, char *username,
+ uint32 smb_userid_low, char lm_chal[8], char lm_chal_resp[24],
+ char nt_chal_resp[24],
+ NET_ID_INFO_CTR *ctr, NET_USER_INFO_3 *user_info3);
+BOOL cli_nt_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr);
+
+/*The following definitions come from rpc_client/cli_lsarpc.c */
+
+BOOL do_lsa_open_policy(struct cli_state *cli,
+ char *server_name, POLICY_HND *hnd);
+BOOL do_lsa_query_info_pol(struct cli_state *cli,
+ POLICY_HND *hnd, uint16 info_class,
+ fstring domain_name, fstring domain_sid);
+BOOL do_lsa_close(struct cli_state *cli, POLICY_HND *hnd);
+
+/*The following definitions come from rpc_client/cli_netlogon.c */
+
+BOOL cli_net_logon_ctrl2(struct cli_state *cli, uint32 status_level);
+BOOL cli_net_auth2(struct cli_state *cli, uint16 sec_chan,
+ uint32 neg_flags, DOM_CHAL *srv_chal);
+BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal);
+BOOL cli_net_srv_pwset(struct cli_state *cli, uint8 hashed_mach_pwd[16]);
+BOOL cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3);
+BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr);
+BOOL change_trust_account_password( char *domain, char *remote_machine_list);
+
+/*The following definitions come from rpc_client/cli_pipe.c */
+
+BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
+ prs_struct *data, prs_struct *rdata);
+BOOL cli_nt_session_open(struct cli_state *cli, char *pipe_name, BOOL encrypted);
+void cli_nt_session_close(struct cli_state *cli);
+
+/*The following definitions come from rpc_client/cli_samr.c */
+
+BOOL get_samr_query_usergroups(struct cli_state *cli,
+ POLICY_HND *pol_open_domain, uint32 user_rid,
+ uint32 *num_groups, DOM_GID *gid);
+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);
+BOOL do_samr_unknown_8(struct cli_state *cli,
+ POLICY_HND *domain_pol, uint16 switch_value);
+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);
+BOOL do_samr_connect(struct cli_state *cli,
+ char *srv_name, uint32 unknown_0,
+ POLICY_HND *connect_pol);
+BOOL do_samr_open_user(struct cli_state *cli,
+ POLICY_HND *pol, uint32 unk_0, uint32 rid,
+ POLICY_HND *user_pol);
+BOOL do_samr_open_domain(struct cli_state *cli,
+ POLICY_HND *connect_pol, uint32 rid, DOM_SID *sid,
+ POLICY_HND *domain_pol);
+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]);
+BOOL do_samr_query_usergroups(struct cli_state *cli,
+ POLICY_HND *pol, uint32 *num_groups, DOM_GID *gid);
+BOOL do_samr_query_userinfo(struct cli_state *cli,
+ POLICY_HND *pol, uint16 switch_value, void* usr);
+BOOL do_samr_close(struct cli_state *cli, POLICY_HND *hnd);
+
+/*The following definitions come from rpc_client/cli_wkssvc.c */
+
+BOOL do_wks_query_info(struct cli_state *cli,
+ char *server_name, uint32 switch_value,
+ WKS_INFO_100 *wks100);
+
+/*The following definitions come from rpc_parse/parse_lsa.c */
+
+void make_lsa_trans_name(LSA_TRANS_NAME *trn, uint32 sid_name_use, char *name, uint32 idx);
+void make_lsa_obj_attr(LSA_OBJ_ATTR *attr, uint32 attributes, uint32 sec_qos);
+void make_q_open_pol(LSA_Q_OPEN_POL *r_q, char *server_name,
+ uint32 attributes, uint32 sec_qos,
+ uint32 desired_access);
+void lsa_io_q_open_pol(char *desc, LSA_Q_OPEN_POL *r_q, prs_struct *ps, int depth);
+void lsa_io_r_open_pol(char *desc, LSA_R_OPEN_POL *r_p, prs_struct *ps, int depth);
+void make_q_query(LSA_Q_QUERY_INFO *q_q, POLICY_HND *hnd, uint16 info_class);
+void lsa_io_q_query(char *desc, LSA_Q_QUERY_INFO *q_q, prs_struct *ps, int depth);
+void lsa_io_q_enum_trust_dom(char *desc, LSA_Q_ENUM_TRUST_DOM *q_e, prs_struct *ps, int depth);
+void make_r_enum_trust_dom(LSA_R_ENUM_TRUST_DOM *r_e,
+ uint32 enum_context, char *domain_name, DOM_SID *domain_sid,
+ uint32 status);
+void lsa_io_r_enum_trust_dom(char *desc, LSA_R_ENUM_TRUST_DOM *r_e, prs_struct *ps, int depth);
+void lsa_io_r_query(char *desc, LSA_R_QUERY_INFO *r_q, prs_struct *ps, int depth);
+void lsa_io_q_lookup_sids(char *desc, LSA_Q_LOOKUP_SIDS *q_s, prs_struct *ps, int depth);
+void lsa_io_r_lookup_sids(char *desc, LSA_R_LOOKUP_SIDS *r_s, prs_struct *ps, int depth);
+void lsa_io_q_lookup_rids(char *desc, LSA_Q_LOOKUP_RIDS *q_r, prs_struct *ps, int depth);
+void lsa_io_r_lookup_rids(char *desc, LSA_R_LOOKUP_RIDS *r_r, prs_struct *ps, int depth);
+void make_lsa_q_close(LSA_Q_CLOSE *q_c, POLICY_HND *hnd);
+void lsa_io_q_close(char *desc, LSA_Q_CLOSE *q_c, prs_struct *ps, int depth);
+void lsa_io_r_close(char *desc, LSA_R_CLOSE *r_c, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_parse/parse_misc.c */
+
+void smb_io_time(char *desc, NTTIME *nttime, prs_struct *ps, int depth);
+void smb_io_lookup_level(char *desc, LOOKUP_LEVEL *level, prs_struct *ps, int depth);
+uint32 get_enum_hnd(ENUM_HND *enh);
+void make_enum_hnd(ENUM_HND *enh, uint32 hnd);
+void smb_io_enum_hnd(char *desc, ENUM_HND *hnd, prs_struct *ps, int depth);
+void smb_io_dom_sid(char *desc, DOM_SID *sid, prs_struct *ps, int depth);
+void make_dom_sid(DOM_SID *sid, char *str_sid);
+void make_dom_sid2(DOM_SID2 *sid2, DOM_SID *sid);
+void smb_io_dom_sid2(char *desc, DOM_SID2 *sid, prs_struct *ps, int depth);
+void make_str_hdr(STRHDR *hdr, int max_len, int len, uint32 buffer);
+void smb_io_strhdr(char *desc, STRHDR *hdr, prs_struct *ps, int depth);
+void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint32 buffer);
+void smb_io_unihdr(char *desc, UNIHDR *hdr, prs_struct *ps, int depth);
+void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate);
+void smb_io_unihdr2(char *desc, UNIHDR2 *hdr2, prs_struct *ps, int depth);
+void make_unistr(UNISTR *str, char *buf);
+void smb_io_unistr(char *desc, UNISTR *uni, prs_struct *ps, int depth);
+void make_uninotstr2(UNINOTSTR2 *str, char *buf, int len);
+void smb_io_uninotstr2(char *desc, UNINOTSTR2 *uni2, uint32 buffer, prs_struct *ps, int depth);
+void make_buf_unistr2(UNISTR2 *str, uint32 *ptr, char *buf);
+void copy_unistr2(UNISTR2 *str, UNISTR2 *from);
+void make_string2(STRING2 *str, char *buf, int len);
+void smb_io_string2(char *desc, STRING2 *str2, uint32 buffer, prs_struct *ps, int depth);
+void make_unistr2(UNISTR2 *str, char *buf, int len);
+void smb_io_unistr2(char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth);
+void make_dom_rid2(DOM_RID2 *rid2, uint32 rid);
+void smb_io_dom_rid2(char *desc, DOM_RID2 *rid2, prs_struct *ps, int depth);
+void make_dom_rid3(DOM_RID3 *rid3, uint32 rid);
+void smb_io_dom_rid3(char *desc, DOM_RID3 *rid3, prs_struct *ps, int depth);
+void make_dom_rid4(DOM_RID4 *rid4, uint16 unknown, uint16 attr, uint32 rid);
+void make_log_info(DOM_LOG_INFO *log, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name);
+void smb_io_log_info(char *desc, DOM_LOG_INFO *log, prs_struct *ps, int depth);
+void smb_io_chal(char *desc, DOM_CHAL *chal, prs_struct *ps, int depth);
+void smb_io_cred(char *desc, DOM_CRED *cred, prs_struct *ps, int depth);
+void make_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred);
+void smb_io_clnt_info2(char *desc, DOM_CLNT_INFO2 *clnt, prs_struct *ps, int depth);
+void make_clnt_info(DOM_CLNT_INFO *clnt,
+ char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name,
+ DOM_CRED *cred);
+void smb_io_clnt_info(char *desc, DOM_CLNT_INFO *clnt, prs_struct *ps, int depth);
+void make_logon_id(DOM_LOGON_ID *log, uint32 log_id_low, uint32 log_id_high);
+void smb_io_logon_id(char *desc, DOM_LOGON_ID *log, prs_struct *ps, int depth);
+void make_owf_info(OWF_INFO *hash, uint8 data[16]);
+void smb_io_owf_info(char *desc, OWF_INFO *hash, prs_struct *ps, int depth);
+void smb_io_gid(char *desc, DOM_GID *gid, prs_struct *ps, int depth);
+void smb_io_pol_hnd(char *desc, POLICY_HND *pol, prs_struct *ps, int depth);
+void smb_io_dom_query_3(char *desc, DOM_QUERY_3 *d_q, prs_struct *ps, int depth);
+void smb_io_dom_query_5(char *desc, DOM_QUERY_3 *d_q, prs_struct *ps, int depth);
+void smb_io_dom_name(char *desc, DOM_NAME *name, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_parse/parse_net.c */
+
+void net_io_q_logon_ctrl2(char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *ps, int depth);
+void make_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);
+void net_io_r_logon_ctrl2(char *desc, NET_R_LOGON_CTRL2 *r_l, prs_struct *ps, int depth);
+void make_r_trust_dom(NET_R_TRUST_DOM_LIST *r_t,
+ uint32 num_doms, char *dom_name);
+void net_io_r_trust_dom(char *desc, NET_R_TRUST_DOM_LIST *r_t, prs_struct *ps, int depth);
+void net_io_q_trust_dom(char *desc, NET_Q_TRUST_DOM_LIST *q_l, prs_struct *ps, int depth);
+void make_q_req_chal(NET_Q_REQ_CHAL *q_c,
+ char *logon_srv, char *logon_clnt,
+ DOM_CHAL *clnt_chal);
+void net_io_q_req_chal(char *desc, NET_Q_REQ_CHAL *q_c, prs_struct *ps, int depth);
+void net_io_r_req_chal(char *desc, NET_R_REQ_CHAL *r_c, prs_struct *ps, int depth);
+void make_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);
+void net_io_q_auth_2(char *desc, NET_Q_AUTH_2 *q_a, prs_struct *ps, int depth);
+void net_io_r_auth_2(char *desc, NET_R_AUTH_2 *r_a, prs_struct *ps, int depth);
+void make_q_srv_pwset(NET_Q_SRV_PWSET *q_s, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name, DOM_CRED *cred, char nt_cypher[16]);
+void net_io_q_srv_pwset(char *desc, NET_Q_SRV_PWSET *q_s, prs_struct *ps, int depth);
+void net_io_r_srv_pwset(char *desc, NET_R_SRV_PWSET *r_s, prs_struct *ps, int depth);
+void make_id_info2(NET_ID_INFO_2 *id, char *domain_name,
+ uint32 param_ctrl, uint32 log_id_low, uint32 log_id_high,
+ char *user_name, char *wksta_name,
+ unsigned char lm_challenge[8],
+ unsigned char lm_chal_resp[24],
+ unsigned char nt_chal_resp[24]);
+void make_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, uint16 validation_level);
+void make_net_user_info3(NET_USER_INFO_3 *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,
+
+ char *user_name,
+ char *full_name,
+ char *logon_script,
+ char *profile_path,
+ char *home_dir,
+ char *dir_drive,
+
+ uint16 logon_count,
+ uint16 bad_pw_count,
+
+ uint32 user_id,
+ uint32 group_id,
+ uint32 num_groups,
+ DOM_GID *gids,
+ uint32 user_flgs,
+
+ char sess_key[16],
+
+ char *logon_srv,
+ char *logon_dom,
+
+ DOM_SID *dom_sid,
+ char *other_sids);
+void net_io_q_sam_logon(char *desc, NET_Q_SAM_LOGON *q_l, prs_struct *ps, int depth);
+void net_io_r_sam_logon(char *desc, NET_R_SAM_LOGON *r_l, prs_struct *ps, int depth);
+void net_io_q_sam_logoff(char *desc, NET_Q_SAM_LOGOFF *q_l, prs_struct *ps, int depth);
+void net_io_r_sam_logoff(char *desc, NET_R_SAM_LOGOFF *r_l, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_parse/parse_prs.c */
+
+void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name);
+void prs_init(prs_struct *ps, uint32 size,
+ uint8 align, uint32 margin,
+ BOOL io);
+void prs_mem_free(prs_struct *ps);
+void prs_align(prs_struct *ps);
+BOOL prs_grow(prs_struct *ps);
+BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8);
+BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16);
+BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32);
+BOOL prs_uint8s(BOOL charmode, char *name, prs_struct *ps, int depth, uint8 *data8s, int len);
+BOOL prs_uint32s(BOOL charmode, char *name, prs_struct *ps, int depth, uint32 *data32s, int len);
+BOOL prs_uninotstr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNINOTSTR2 *str);
+BOOL prs_string2(BOOL charmode, char *name, prs_struct *ps, int depth, STRING2 *str);
+BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str);
+BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str);
+BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, uint16 len);
+
+/*The following definitions come from rpc_parse/parse_reg.c */
+
+void reg_io_q_open_policy(char *desc, REG_Q_OPEN_POLICY *r_q, prs_struct *ps, int depth);
+void reg_io_r_open_policy(char *desc, REG_R_OPEN_POLICY *r_r, prs_struct *ps, int depth);
+void reg_io_q_close(char *desc, REG_Q_CLOSE *q_u, prs_struct *ps, int depth);
+void reg_io_r_close(char *desc, REG_R_CLOSE *r_u, prs_struct *ps, int depth);
+void reg_io_q_info(char *desc, REG_Q_INFO *r_q, prs_struct *ps, int depth);
+void make_reg_r_info(REG_R_INFO *r_r,
+ uint32 level, char *os_type,
+ uint32 unknown_0, uint32 unknown_1,
+ uint32 status);
+void reg_io_r_info(char *desc, REG_R_INFO *r_r, prs_struct *ps, int depth);
+void reg_io_q_open_entry(char *desc, REG_Q_OPEN_ENTRY *r_q, prs_struct *ps, int depth);
+void make_reg_r_open_entry(REG_R_OPEN_ENTRY *r_r,
+ POLICY_HND *pol, uint32 status);
+void reg_io_r_open_entry(char *desc, REG_R_OPEN_ENTRY *r_r, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_parse/parse_rpc.c */
+
+void make_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 flags,
+ uint32 call_id, int data_len, int auth_len);
+void smb_io_rpc_hdr(char *desc, RPC_HDR *rpc, prs_struct *ps, int depth);
+void make_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);
+void smb_io_rpc_hdr_rb(char *desc, RPC_HDR_RB *rpc, prs_struct *ps, int depth);
+void make_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);
+void smb_io_rpc_hdr_ba(char *desc, RPC_HDR_BA *rpc, prs_struct *ps, int depth);
+void make_rpc_hdr_req(RPC_HDR_REQ *hdr, uint32 data_len, uint16 opnum);
+void smb_io_rpc_hdr_req(char *desc, RPC_HDR_REQ *rpc, prs_struct *ps, int depth);
+void smb_io_rpc_hdr_resp(char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth);
+void make_rpc_auth_ntlmssp_req(RPC_AUTH_NTLMSSP_REQ *req,
+ fstring ntlmssp_str, uint32 ntlmssp_ver,
+ uint32 unknown_0, fstring myname, fstring domain);
+void smb_io_rpc_auth_ntlmssp_req(char *desc, RPC_AUTH_NTLMSSP_REQ *req, prs_struct *ps, int depth);
+void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp,
+ uint8 auth_type, uint8 auth_level, uint8 stub_type_len,
+ fstring ntlmssp_str, uint32 ntlmssp_ver,
+ uint32 unknown_1, uint32 unknown_2, uint32 unknown_3,
+ uint8 data[16]);
+void smb_io_rpc_auth_ntlmssp_resp(char *desc, RPC_AUTH_NTLMSSP_RESP *rsp, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_parse/parse_samr.c */
+
+void make_samr_q_close_hnd(SAMR_Q_CLOSE_HND *q_c, POLICY_HND *hnd);
+void samr_io_q_close_hnd(char *desc, SAMR_Q_CLOSE_HND *q_u, prs_struct *ps, int depth);
+void samr_io_r_close_hnd(char *desc, SAMR_R_CLOSE_HND *r_u, prs_struct *ps, int depth);
+void make_samr_q_open_domain(SAMR_Q_OPEN_DOMAIN *q_u,
+ POLICY_HND *connect_pol, uint32 rid,
+ DOM_SID *sid);
+void samr_io_q_open_domain(char *desc, SAMR_Q_OPEN_DOMAIN *q_u, prs_struct *ps, int depth);
+void samr_io_r_open_domain(char *desc, SAMR_R_OPEN_DOMAIN *r_u, prs_struct *ps, int depth);
+void make_samr_q_unknown_3(SAMR_Q_UNKNOWN_3 *q_u,
+ POLICY_HND *user_pol, uint16 switch_value);
+void samr_io_q_unknown_3(char *desc, SAMR_Q_UNKNOWN_3 *q_u, prs_struct *ps, int depth);
+void make_samr_q_unknown_8(SAMR_Q_UNKNOWN_8 *q_u,
+ POLICY_HND *domain_pol, uint16 switch_value);
+void samr_io_q_unknown_8(char *desc, SAMR_Q_UNKNOWN_8 *q_u, prs_struct *ps, int depth);
+void make_dom_sid3(DOM_SID3 *sid3, uint16 unk_0, uint16 unk_1, DOM_SID *sid);
+void make_samr_r_unknown_3(SAMR_R_UNKNOWN_3 *r_u,
+ uint16 unknown_2, uint16 unknown_3,
+ uint32 unknown_4, uint16 unknown_6, uint16 unknown_7,
+ int num_sid3s, DOM_SID3 sid3[MAX_SAM_SIDS],
+ uint32 status);
+void samr_io_r_unknown_3(char *desc, SAMR_R_UNKNOWN_3 *r_u, prs_struct *ps, int depth);
+void make_samr_q_enum_dom_users(SAMR_Q_ENUM_DOM_USERS *q_e, POLICY_HND *pol,
+ uint16 req_num_entries, uint16 unk_0,
+ uint16 acb_mask, uint16 unk_1, uint32 size);
+void samr_io_q_enum_dom_users(char *desc, SAMR_Q_ENUM_DOM_USERS *q_e, prs_struct *ps, int depth);
+void make_samr_r_enum_dom_users(SAMR_R_ENUM_DOM_USERS *r_u,
+ uint16 total_num_entries, uint16 unk_0,
+ uint32 num_sam_entries, SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES], uint32 status);
+void samr_io_r_enum_dom_users(char *desc, SAMR_R_ENUM_DOM_USERS *r_u, prs_struct *ps, int depth);
+void make_samr_q_enum_dom_aliases(SAMR_Q_ENUM_DOM_ALIASES *q_e, POLICY_HND *pol, uint32 size);
+void samr_io_q_enum_dom_aliases(char *desc, SAMR_Q_ENUM_DOM_ALIASES *q_e, prs_struct *ps, int depth);
+void make_samr_r_enum_dom_aliases(SAMR_R_ENUM_DOM_ALIASES *r_u,
+ uint32 num_sam_entries, SAM_USER_INFO_21 grps[MAX_SAM_ENTRIES],
+ uint32 status);
+void samr_io_r_enum_dom_aliases(char *desc, SAMR_R_ENUM_DOM_ALIASES *r_u, prs_struct *ps, int depth);
+void make_samr_q_query_dispinfo(SAMR_Q_QUERY_DISPINFO *q_e, POLICY_HND *pol,
+ uint16 switch_level, uint32 start_idx, uint32 size);
+void samr_io_q_query_dispinfo(char *desc, SAMR_Q_QUERY_DISPINFO *q_e, prs_struct *ps, int depth);
+void make_sam_info_2(SAM_INFO_2 *sam, uint32 acb_mask,
+ uint32 start_idx, uint32 num_sam_entries,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES]);
+void make_sam_info_1(SAM_INFO_1 *sam, uint32 acb_mask,
+ uint32 start_idx, uint32 num_sam_entries,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES]);
+void make_samr_r_query_dispinfo(SAMR_R_QUERY_DISPINFO *r_u,
+ uint16 switch_level, SAM_INFO_CTR *ctr, uint32 status);
+void samr_io_r_query_dispinfo(char *desc, SAMR_R_QUERY_DISPINFO *r_u, prs_struct *ps, int depth);
+void make_samr_q_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_e, POLICY_HND *pol,
+ uint16 switch_level, uint32 start_idx, uint32 size);
+void samr_io_q_enum_dom_groups(char *desc, SAMR_Q_ENUM_DOM_GROUPS *q_e, prs_struct *ps, int depth);
+void make_samr_r_enum_dom_groups(SAMR_R_ENUM_DOM_GROUPS *r_u,
+ uint32 start_idx, uint32 num_sam_entries,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES],
+ uint32 status);
+void samr_io_r_enum_dom_groups(char *desc, SAMR_R_ENUM_DOM_GROUPS *r_u, prs_struct *ps, int depth);
+void make_samr_q_query_aliasinfo(SAMR_Q_QUERY_ALIASINFO *q_e,
+ POLICY_HND *pol,
+ uint16 switch_level);
+void samr_io_q_query_aliasinfo(char *desc, SAMR_Q_QUERY_ALIASINFO *q_e, prs_struct *ps, int depth);
+void make_samr_r_query_aliasinfo(SAMR_R_QUERY_ALIASINFO *r_u,
+ uint16 switch_value, char *acct_desc,
+ uint32 status);
+void samr_io_r_query_aliasinfo(char *desc, SAMR_R_QUERY_ALIASINFO *r_u, prs_struct *ps, int depth);
+void samr_io_q_lookup_ids(char *desc, SAMR_Q_LOOKUP_IDS *q_u, prs_struct *ps, int depth);
+void make_samr_r_lookup_ids(SAMR_R_LOOKUP_IDS *r_u,
+ uint32 num_rids, uint32 *rid, uint32 status);
+void samr_io_r_lookup_ids(char *desc, SAMR_R_LOOKUP_IDS *r_u, prs_struct *ps, int depth);
+void samr_io_q_lookup_names(char *desc, SAMR_Q_LOOKUP_NAMES *q_u, prs_struct *ps, int depth);
+void make_samr_r_lookup_names(SAMR_R_LOOKUP_NAMES *r_u,
+ uint32 num_rids, uint32 *rid, uint32 status);
+void samr_io_r_lookup_names(char *desc, SAMR_R_LOOKUP_NAMES *r_u, prs_struct *ps, int depth);
+void samr_io_q_unknown_12(char *desc, SAMR_Q_UNKNOWN_12 *q_u, prs_struct *ps, int depth);
+void make_samr_r_unknown_12(SAMR_R_UNKNOWN_12 *r_u,
+ uint32 num_aliases, fstring *als_name, uint32 *num_als_usrs,
+ uint32 status);
+void samr_io_r_unknown_12(char *desc, SAMR_R_UNKNOWN_12 *r_u, prs_struct *ps, int depth);
+void make_samr_q_open_user(SAMR_Q_OPEN_USER *q_u,
+ POLICY_HND *pol,
+ uint32 unk_0, uint32 rid);
+void samr_io_q_open_user(char *desc, SAMR_Q_OPEN_USER *q_u, prs_struct *ps, int depth);
+void samr_io_r_open_user(char *desc, SAMR_R_OPEN_USER *r_u, prs_struct *ps, int depth);
+void make_samr_q_query_usergroups(SAMR_Q_QUERY_USERGROUPS *q_u,
+ POLICY_HND *hnd);
+void samr_io_q_query_usergroups(char *desc, SAMR_Q_QUERY_USERGROUPS *q_u, prs_struct *ps, int depth);
+void make_samr_r_query_usergroups(SAMR_R_QUERY_USERGROUPS *r_u,
+ uint32 num_gids, DOM_GID *gid, uint32 status);
+void samr_io_r_query_usergroups(char *desc, SAMR_R_QUERY_USERGROUPS *r_u, prs_struct *ps, int depth);
+void make_samr_q_query_userinfo(SAMR_Q_QUERY_USERINFO *q_u,
+ POLICY_HND *hnd, uint16 switch_value);
+void samr_io_q_query_userinfo(char *desc, SAMR_Q_QUERY_USERINFO *q_u, prs_struct *ps, int depth);
+void make_sam_user_info21(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,
+
+ char *user_name,
+ char *full_name,
+ char *home_dir,
+ char *dir_drive,
+ char *logon_script,
+ char *profile_path,
+ char *description,
+ char *workstations,
+ char *unknown_str,
+ char *munged_dial,
+
+ uint32 user_rid,
+ uint32 group_rid,
+ uint16 acb_info,
+
+ uint32 unknown_3,
+ uint16 logon_divs,
+ LOGON_HRS *hrs,
+ uint32 unknown_5,
+ uint32 unknown_6);
+void make_samr_r_query_userinfo(SAMR_R_QUERY_USERINFO *r_u,
+ uint16 switch_value, void *info, uint32 status);
+void samr_io_r_query_userinfo(char *desc, SAMR_R_QUERY_USERINFO *r_u, prs_struct *ps, int depth);
+void samr_io_q_unknown_32(char *desc, SAMR_Q_UNKNOWN_32 *q_u, prs_struct *ps, int depth);
+void samr_io_r_unknown_32(char *desc, SAMR_R_UNKNOWN_32 *r_u, prs_struct *ps, int depth);
+void make_samr_q_connect(SAMR_Q_CONNECT *q_u,
+ char *srv_name, uint32 unknown_0);
+void samr_io_q_connect(char *desc, SAMR_Q_CONNECT *q_u, prs_struct *ps, int depth);
+void samr_io_r_connect(char *desc, SAMR_R_CONNECT *r_u, prs_struct *ps, int depth);
+void make_samr_q_open_alias(SAMR_Q_OPEN_ALIAS *q_u,
+ uint32 unknown_0, uint32 rid);
+void samr_io_q_open_alias(char *desc, SAMR_Q_OPEN_ALIAS *q_u, prs_struct *ps, int depth);
+void samr_io_r_open_alias(char *desc, SAMR_R_OPEN_ALIAS *r_u, prs_struct *ps, int depth);
+void make_samr_q_unknown_38(SAMR_Q_UNKNOWN_38 *q_u, char *srv_name);
+void samr_io_q_unknown_38(char *desc, SAMR_Q_UNKNOWN_38 *q_u, prs_struct *ps, int depth);
+void make_samr_r_unknown_38(SAMR_R_UNKNOWN_38 *r_u,
+ uint16 level, uint32 status);
+void samr_io_r_unknown_38(char *desc, SAMR_R_UNKNOWN_38 *r_u, prs_struct *ps, int depth);
+void samr_io_enc_passwd(char *desc, SAMR_ENC_PASSWD *pwd, prs_struct *ps, int depth);
+void samr_io_enc_hash(char *desc, SAMR_ENC_HASH *hsh, prs_struct *ps, int depth);
+void make_samr_q_unknown_12(SAMR_Q_UNKNOWN_12 *q_u,
+ POLICY_HND *pol, uint32 rid,
+ uint32 num_gids, uint32 *gid);
+void make_samr_q_unknown_21(SAMR_Q_UNKNOWN_21 *q_c,
+ POLICY_HND *hnd, uint16 unk_1, uint16 unk_2);
+void make_samr_q_unknown_13(SAMR_Q_UNKNOWN_13 *q_c,
+ POLICY_HND *hnd, uint16 unk_1, uint16 unk_2);
+
+/*The following definitions come from rpc_parse/parse_srv.c */
+
+void make_srv_share_info1_str(SH_INFO_1_STR *sh1, char *net_name, char *remark);
+void make_srv_share_info1(SH_INFO_1 *sh1, char *net_name, uint32 type, char *remark);
+void make_srv_share_info2_str(SH_INFO_2_STR *sh2,
+ char *net_name, char *remark,
+ char *path, char *passwd);
+void make_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);
+void srv_io_q_net_share_enum(char *desc, SRV_Q_NET_SHARE_ENUM *q_n, prs_struct *ps, int depth);
+void srv_io_r_net_share_enum(char *desc, SRV_R_NET_SHARE_ENUM *r_n, prs_struct *ps, int depth);
+void make_srv_sess_info0_str(SESS_INFO_0_STR *ss0, char *name);
+void make_srv_sess_info0(SESS_INFO_0 *ss0, char *name);
+void make_srv_sess_info1_str(SESS_INFO_1_STR *ss1, char *name, char *user);
+void make_srv_sess_info1(SESS_INFO_1 *ss1,
+ char *name, char *user,
+ uint32 num_opens, uint32 open_time, uint32 idle_time,
+ uint32 user_flags);
+void srv_io_q_net_sess_enum(char *desc, SRV_Q_NET_SESS_ENUM *q_n, prs_struct *ps, int depth);
+void srv_io_r_net_sess_enum(char *desc, SRV_R_NET_SESS_ENUM *r_n, prs_struct *ps, int depth);
+void make_srv_conn_info0(CONN_INFO_0 *ss0, uint32 id);
+void make_srv_conn_info1_str(CONN_INFO_1_STR *ss1, char *usr_name, char *net_name);
+void make_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);
+void srv_io_q_net_conn_enum(char *desc, SRV_Q_NET_CONN_ENUM *q_n, prs_struct *ps, int depth);
+void srv_io_r_net_conn_enum(char *desc, SRV_R_NET_CONN_ENUM *r_n, prs_struct *ps, int depth);
+void make_srv_file_info3_str(FILE_INFO_3_STR *fi3, char *user_name, char *path_name);
+void make_srv_file_info3(FILE_INFO_3 *fl3,
+ uint32 id, uint32 perms, uint32 num_locks,
+ char *path_name, char *user_name);
+void srv_io_q_net_file_enum(char *desc, SRV_Q_NET_FILE_ENUM *q_n, prs_struct *ps, int depth);
+void srv_io_r_net_file_enum(char *desc, SRV_R_NET_FILE_ENUM *r_n, prs_struct *ps, int depth);
+void make_srv_info_101(SRV_INFO_101 *sv101, uint32 platform_id, char *name,
+ uint32 ver_major, uint32 ver_minor,
+ uint32 srv_type, char *comment);
+void make_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);
+void srv_io_q_net_srv_get_info(char *desc, SRV_Q_NET_SRV_GET_INFO *q_n, prs_struct *ps, int depth);
+void make_srv_r_net_srv_get_info(SRV_R_NET_SRV_GET_INFO *srv,
+ uint32 switch_value, SRV_INFO_CTR *ctr, uint32 status);
+void srv_io_r_net_srv_get_info(char *desc, SRV_R_NET_SRV_GET_INFO *r_n, prs_struct *ps, int depth);
+void srv_io_q_net_remote_tod(char *desc, SRV_Q_NET_REMOTE_TOD *q_n, prs_struct *ps, int depth);
+void make_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);
+void srv_io_r_net_remote_tod(char *desc, SRV_R_NET_REMOTE_TOD *r_n, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_parse/parse_wks.c */
+
+void make_wks_q_query_info(WKS_Q_QUERY_INFO *q_u,
+ char *server, uint16 switch_value) ;
+void wks_io_q_query_info(char *desc, WKS_Q_QUERY_INFO *q_u, prs_struct *ps, int depth);
+void make_wks_info_100(WKS_INFO_100 *inf,
+ uint32 platform_id, uint32 ver_major, uint32 ver_minor,
+ char *my_name, char *domain_name);
+void make_wks_r_query_info(WKS_R_QUERY_INFO *r_u,
+ uint32 switch_value, WKS_INFO_100 *wks100,
+ int status) ;
+void wks_io_r_query_info(char *desc, WKS_R_QUERY_INFO *r_u, prs_struct *ps, int depth);
+
+/*The following definitions come from rpc_server/srv_ldap_helpers.c */
+
+void ldap_helper_dummy(void);
+
+/*The following definitions come from rpc_server/srv_lsa.c */
+
+BOOL api_ntlsa_rpc(pipes_struct *p, prs_struct *data);
+
+/*The following definitions come from rpc_server/srv_lsa_hnd.c */
+
+void init_lsa_policy_hnd(void);
+BOOL open_lsa_policy_hnd(POLICY_HND *hnd);
+int find_lsa_policy_by_hnd(POLICY_HND *hnd);
+BOOL set_lsa_policy_samr_rid(POLICY_HND *hnd, uint32 rid);
+BOOL set_lsa_policy_samr_pol_status(POLICY_HND *hnd, uint32 pol_status);
+BOOL set_lsa_policy_samr_sid(POLICY_HND *hnd, DOM_SID *sid);
+uint32 get_lsa_policy_samr_rid(POLICY_HND *hnd);
+BOOL set_lsa_policy_reg_name(POLICY_HND *hnd, fstring name);
+BOOL close_lsa_policy_hnd(POLICY_HND *hnd);
+
+/*The following definitions come from rpc_server/srv_netlog.c */
+
+BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data);
+
+/*The following definitions come from rpc_server/srv_pipe_hnd.c */
+
+void reset_chain_p(void);
+void init_rpc_pipe_hnd(void);
+pipes_struct *open_rpc_pipe_p(char *pipe_name,
+ connection_struct *conn, uint16 vuid);
+int read_pipe(pipes_struct *p, char *data, uint32 pos, int n);
+BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state);
+BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn);
+pipes_struct *get_rpc_pipe_p(char *buf, int where);
+pipes_struct *get_rpc_pipe(int pnum);
+
+/*The following definitions come from rpc_server/srv_reg.c */
+
+BOOL api_reg_rpc(pipes_struct *p, prs_struct *data);
+
+/*The following definitions come from rpc_server/srv_samr.c */
+
+BOOL api_samr_rpc(pipes_struct *p, prs_struct *data);
+
+/*The following definitions come from rpc_server/srv_srvsvc.c */
+
+BOOL api_srvsvc_rpc(pipes_struct *p, prs_struct *data);
+
+/*The following definitions come from rpc_server/srv_util.c */
+
+int make_dom_gids(char *gids_str, DOM_GID **ppgids);
+BOOL create_rpc_reply(pipes_struct *p,
+ uint32 data_start, uint32 data_end);
+BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds,
+ prs_struct *data);
+void get_domain_user_groups(char *domain_groups, char *user);
+uint32 lookup_group_name(uint32 rid, char *group_name, uint32 *type);
+uint32 lookup_alias_name(uint32 rid, char *alias_name, uint32 *type);
+uint32 lookup_user_name(uint32 rid, char *user_name, uint32 *type);
+uint32 lookup_group_rid(char *group_name, uint32 *rid);
+uint32 lookup_alias_rid(char *alias_name, uint32 *rid);
+uint32 lookup_user_rid(char *user_name, uint32 *rid);
+
+/*The following definitions come from rpc_server/srv_wkssvc.c */
+
+BOOL api_wkssvc_rpc(pipes_struct *p, prs_struct *data);
+
+/*The following definitions come from rpcclient/cmd_lsarpc.c */
+
+void cmd_lsa_query_info(struct client_info *info);
+
+/*The following definitions come from rpcclient/cmd_samr.c */
+
+void cmd_sam_test(struct client_info *info);
+void cmd_sam_enum_users(struct client_info *info);
+void cmd_sam_query_user(struct client_info *info);
+void cmd_sam_query_groups(struct client_info *info);
+void cmd_sam_enum_aliases(struct client_info *info);
+
+/*The following definitions come from rpcclient/cmd_wkssvc.c */
+
+void cmd_wks_query_info(struct client_info *info);
+
+/*The following definitions come from rpcclient/display.c */
+
+char *get_file_mode_str(uint32 share_mode);
+char *get_file_oplock_str(uint32 op_type);
+char *get_share_type_str(uint32 type);
+char *get_server_type_str(uint32 type);
+void display_srv_info_101(FILE *out_hnd, enum action_type action,
+ SRV_INFO_101 *sv101);
+void display_srv_info_102(FILE *out_hnd, enum action_type action,SRV_INFO_102 *sv102);
+void display_srv_info_ctr(FILE *out_hnd, enum action_type action,SRV_INFO_CTR *ctr);
+void display_conn_info_0(FILE *out_hnd, enum action_type action,
+ CONN_INFO_0 *info0);
+void display_conn_info_1(FILE *out_hnd, enum action_type action,
+ CONN_INFO_1 *info1, CONN_INFO_1_STR *str1);
+void display_srv_conn_info_0_ctr(FILE *out_hnd, enum action_type action,
+ SRV_CONN_INFO_0 *ctr);
+void display_srv_conn_info_1_ctr(FILE *out_hnd, enum action_type action,
+ SRV_CONN_INFO_1 *ctr);
+void display_srv_conn_info_ctr(FILE *out_hnd, enum action_type action,
+ SRV_CONN_INFO_CTR *ctr);
+void display_share_info_1(FILE *out_hnd, enum action_type action,
+ SH_INFO_1 *info1, SH_INFO_1_STR *str1);
+void display_share_info_2(FILE *out_hnd, enum action_type action,
+ SH_INFO_2 *info2, SH_INFO_2_STR *str2);
+void display_srv_share_info_1_ctr(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_1 *ctr);
+void display_srv_share_info_2_ctr(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_2 *ctr);
+void display_srv_share_info_ctr(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_CTR *ctr);
+void display_file_info_3(FILE *out_hnd, enum action_type action,
+ FILE_INFO_3 *info3, FILE_INFO_3_STR *str3);
+void display_srv_file_info_3_ctr(FILE *out_hnd, enum action_type action,
+ SRV_FILE_INFO_3 *ctr);
+void display_srv_file_info_ctr(FILE *out_hnd, enum action_type action,
+ SRV_FILE_INFO_CTR *ctr);
+void display_server(FILE *out_hnd, enum action_type action,
+ char *sname, uint32 type, char *comment);
+void display_share(FILE *out_hnd, enum action_type action,
+ char *sname, uint32 type, char *comment);
+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);
+void display_name(FILE *out_hnd, enum action_type action,
+ char *sname);
+void display_group_rid_info(FILE *out_hnd, enum action_type action,
+ uint32 num_gids, DOM_GID *gid);
+void display_alias_name_info(FILE *out_hnd, enum action_type action,
+ uint32 num_aliases, fstring *alias_name, uint32 *num_als_usrs);
+void display_sam_user_info_21(FILE *out_hnd, enum action_type action, SAM_USER_INFO_21 *usr);
+
+/*The following definitions come from rpcclient/rpcclient.c */
+
+void rpcclient_init(void);
+
+/*The following definitions come from smbd/blocking.c */
+
+BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num);
+void remove_pending_lock_requests_by_fid(files_struct *fsp);
+void remove_pending_lock_requests_by_mid(int mid);
+void process_blocking_lock_queue(time_t t);
+
+/*The following definitions come from smbd/chgpasswd.c */
+
+BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root);
+BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root);
+BOOL check_lanman_password(char *user, unsigned char *pass1,
+ unsigned char *pass2, struct smb_passwd **psmbpw);
+BOOL change_lanman_password(struct smb_passwd *smbpw, unsigned char *pass1, unsigned char *pass2);
+BOOL check_oem_password(char *user, unsigned char *data,
+ struct smb_passwd **psmbpw, char *new_passwd,
+ int new_passwd_size);
+BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override);
+
+/*The following definitions come from smbd/close.c */
+
+void close_file(files_struct *fsp, BOOL normal_close);
+void close_directory(files_struct *fsp);
+
+/*The following definitions come from smbd/conn.c */
+
+void conn_init(void);
+int conn_num_open(void);
+BOOL conn_snum_used(int snum);
+connection_struct *conn_find(int cnum);
+connection_struct *conn_new(void);
+void conn_close_all(void);
+BOOL conn_idle_all(time_t t, int deadtime);
+void conn_free(connection_struct *conn);
+
+/*The following definitions come from smbd/connection.c */
+
+BOOL yield_connection(connection_struct *conn,char *name,int max_connections);
+BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear);
+
+/*The following definitions come from smbd/dfree.c */
+
+SMB_BIG_UINT sys_disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize);
+
+/*The following definitions come from smbd/dir.c */
+
+void init_dptrs(void);
+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_closecnum(connection_struct *conn);
+void dptr_idlecnum(connection_struct *conn);
+void dptr_closepath(char *path,int pid);
+int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid);
+BOOL dptr_fill(char *buf1,unsigned int key);
+BOOL dptr_zero(char *buf);
+void *dptr_fetch(char *buf,int *num);
+void *dptr_fetch_lanman2(int dptr_num);
+BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype);
+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);
+void *OpenDir(connection_struct *conn, char *name, BOOL use_veto);
+void CloseDir(void *p);
+char *ReadDirName(void *p);
+BOOL SeekDir(void *p,int pos);
+int TellDir(void *p);
+void DirCacheAdd( char *path, char *name, char *dname, int snum );
+char *DirCacheCheck( char *path, char *name, int snum );
+void DirCacheFlush(int snum);
+
+/*The following definitions come from smbd/dosmode.c */
+
+mode_t unix_mode(connection_struct *conn,int dosmode);
+int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf);
+int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st);
+int file_utime(connection_struct *conn, char *fname, struct utimbuf *times);
+BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime);
+
+/*The following definitions come from smbd/error.c */
+
+int cached_error_packet(char *inbuf,char *outbuf,files_struct *fsp,int line);
+int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
+int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
+
+/*The following definitions come from smbd/fileio.c */
+
+SMB_OFF_T seek_file(files_struct *fsp,SMB_OFF_T pos);
+ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n);
+ssize_t write_file(files_struct *fsp,char *data,size_t n);
+void sync_file(connection_struct *conn, files_struct *fsp);
+
+/*The following definitions come from smbd/filename.c */
+
+void print_stat_cache_statistics(void);
+BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
+ BOOL *bad_path, SMB_STRUCT_STAT *pst);
+BOOL check_name(char *name,connection_struct *conn);
+
+/*The following definitions come from smbd/files.c */
+
+files_struct *file_new(void );
+file_fd_struct *fd_get_already_open(SMB_STRUCT_STAT *sbuf);
+file_fd_struct *fd_get_new(void);
+void file_close_conn(connection_struct *conn);
+void file_init(void);
+void file_close_user(int vuid);
+files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval);
+files_struct *file_find_print(void);
+void file_sync_all(connection_struct *conn);
+void fd_ptr_free(file_fd_struct *fd_ptr);
+void file_free(files_struct *fsp);
+files_struct *file_fsp(char *buf, int where);
+void file_chain_reset(void);
+void file_chain_save(void);
+void file_chain_restore(void);
+
+/*The following definitions come from smbd/ipc.c */
+
+int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize);
+
+/*The following definitions come from smbd/mangle.c */
+
+BOOL is_mangled( char *s );
+BOOL is_8_3( char *fname, BOOL check_case );
+void reset_mangled_cache( void );
+BOOL check_mangled_cache( char *s );
+void mangle_name_83( char *s);
+BOOL name_map_mangle(char *OutName, BOOL need83, int snum);
+
+/*The following definitions come from smbd/message.c */
+
+int reply_sends(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_sendstrt(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_sendtxt(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_sendend(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+
+/*The following definitions come from smbd/negprot.c */
+
+int reply_negprot(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size,
+ int dum_buffsize);
+
+/*The following definitions come from smbd/nttrans.c */
+
+int reply_ntcreate_and_X(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+int reply_ntcancel(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+int reply_nttranss(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp);
+void process_pending_change_notify_queue(time_t t);
+int reply_nttrans(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+
+/*The following definitions come from smbd/open.c */
+
+void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u);
+uint16 fd_attempt_close(file_fd_struct *fd_ptr);
+void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int share_mode,int ofun,
+ mode_t mode,int oplock_request, int *Access,int *action);
+int open_directory(files_struct *fsp,connection_struct *conn,
+ char *fname, int smb_ofun, mode_t unixmode, int *action);
+BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op);
+
+/*The following definitions come from smbd/oplock.c */
+
+BOOL open_oplock_ipc(void);
+BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout);
+BOOL set_file_oplock(files_struct *fsp);
+int setup_oplock_select_set( fd_set *fds);
+BOOL process_local_message(char *buffer, int buf_size);
+BOOL request_oplock_break(share_mode_entry *share_entry,
+ SMB_DEV_T dev, SMB_INO_T inode);
+BOOL attempt_close_oplocked_file(files_struct *fsp);
+void check_kernel_oplocks(void);
+
+/*The following definitions come from smbd/password.c */
+
+void generate_next_challenge(char *challenge);
+BOOL set_challenge(unsigned char *challenge);
+user_struct *get_valid_user_struct(uint16 vuid);
+void invalidate_vuid(uint16 vuid);
+char *validated_username(uint16 vuid);
+int setup_groups(char *user, int uid, int gid, int *p_ngroups, GID_T **p_groups);
+uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest);
+void add_session_user(char *user);
+BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8);
+BOOL smb_password_ok(struct smb_passwd *smb_pass,
+ uchar lm_pass[24], uchar nt_pass[24]);
+BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd);
+BOOL user_ok(char *user,int snum);
+BOOL authorise_login(int snum,char *user,char *password, int pwlen,
+ BOOL *guest,BOOL *force,uint16 vuid);
+BOOL check_hosts_equiv(char *user);
+struct cli_state *server_client(void);
+struct cli_state *server_cryptkey(void);
+BOOL server_validate(char *user, char *domain,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen);
+BOOL domain_client_validate( char *user, char *domain,
+ char *smb_apasswd, int smb_apasslen,
+ char *smb_ntpasswd, int smb_ntpasslen);
+
+/*The following definitions come from smbd/pipes.c */
+
+int reply_open_pipe_and_X(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize);
+int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf);
+
+/*The following definitions come from smbd/predict.c */
+
+ssize_t read_predict(int fd,SMB_OFF_T offset,char *buf,char **ptr,size_t num);
+void do_read_prediction(void);
+void invalidate_read_prediction(int fd);
+
+/*The following definitions come from smbd/process.c */
+
+BOOL push_oplock_pending_smb_message(char *buf, int msg_len);
+BOOL receive_next_smb(char *inbuf, int bufsize, int timeout);
+void process_smb(char *inbuf, char *outbuf);
+char *smb_fn_name(int type);
+void construct_reply_common(char *inbuf,char *outbuf);
+int chain_reply(char *inbuf,char *outbuf,int size,int bufsize);
+void smbd_process(void);
+
+/*The following definitions come from smbd/quotas.c */
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+
+/*The following definitions come from smbd/reply.c */
+
+int reply_special(char *inbuf,char *outbuf);
+int reply_tcon(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_unknown(char *inbuf,char *outbuf);
+int reply_ioctl(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize);
+int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz);
+int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,int dum_buffsize);
+int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_exit(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_close(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_writeclose(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_lock(connection_struct *conn,
+ char *inbuf,char *outbuf, int length, int dum_buffsize);
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_tdis(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_echo(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_printopen(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_printclose(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_printqueue(connection_struct *conn,
+ char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int rename_internals(connection_struct *conn,
+ char *inbuf, char *outbuf, char *name,
+ char *newname, BOOL replace_if_exists);
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize);
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize);
+
+/*The following definitions come from smbd/server.c */
+
+BOOL reload_services(BOOL test);
+void exit_server(char *reason);
+
+/*The following definitions come from smbd/service.c */
+
+BOOL become_service(connection_struct *conn,BOOL do_chdir);
+int find_service(char *service);
+connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode);
+void close_cnum(connection_struct *conn, uint16 vuid);
+
+/*The following definitions come from smbd/ssl.c */
+
+int sslutil_init(int isServer);
+int sslutil_accept(int fd);
+int sslutil_fd_is_ssl(int fd);
+int sslutil_connect(int fd);
+int sslutil_disconnect(int fd);
+int sslutil_negotiate_ssl(int fd, int msg_type);
+
+/*The following definitions come from smbd/trans2.c */
+
+void mask_convert( char *mask);
+int reply_findclose(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+int reply_findnclose(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+int reply_transs2(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+int reply_trans2(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize);
+
+/*The following definitions come from smbd/uid.c */
+
+void init_uid(void);
+BOOL become_guest(void);
+BOOL become_user(connection_struct *conn, uint16 vuid);
+BOOL unbecome_user(void );
+void become_root(BOOL save_dir) ;
+void unbecome_root(BOOL restore_dir);
+
+/*The following definitions come from web/cgi.c */
+
+void cgi_load_variables(FILE *f1);
+char *cgi_variable(char *name);
+void cgi_setup(char *rootdir, int auth_required);
+char *cgi_baseurl(void);
+char *cgi_pathinfo(void);
+char *cgi_remote_host(void);
+char *cgi_remote_addr(void);
+BOOL cgi_waspost(void);
+
+/*The following definitions come from web/diagnose.c */
+
+BOOL nmbd_running(void);
+BOOL smbd_running(void);
+
+/*The following definitions come from web/startstop.c */
+
+void start_smbd(void);
+void start_nmbd(void);
+void stop_smbd(void);
+void stop_nmbd(void);
+void kill_pid(pid_t pid);
+
+/*The following definitions come from web/statuspage.c */
+
+void status_page(void);
+
+/*The following definitions come from web/swat.c */
+
+#endif /* _PROTO_H_ */
diff --git a/source/include/rpc_dce.h b/source/include/rpc_dce.h
new file mode 100644
index 00000000000..2e3995e43d7
--- /dev/null
+++ b/source/include/rpc_dce.h
@@ -0,0 +1,219 @@
+/*
+ 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_BIND = 0x0B,
+ RPC_BINDACK = 0x0C
+};
+
+/* DCE/RPC flags */
+#define RPC_FLG_FIRST 0x01
+#define RPC_FLG_LAST 0x02
+
+
+/* RPC_IFACE */
+typedef struct rpc_iface_info
+{
+ uint8 data[16]; /* 16 bytes of rpc interface identification */
+ uint32 version; /* the interface version number */
+
+} RPC_IFACE;
+
+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 */
+ uint32 pack_type; /* 0x1000 0000 - 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;
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+/* this is TEMPORARY */
+/* RPC_AUTH_VERIFIER */
+typedef struct rpc_auth_verif_info
+{
+ fstring ssp_str;
+ uint32 ssp_ver;
+
+} RPC_AUTH_VERIFIER;
+
+/* this is TEMPORARILY coded up as a specific structure */
+/* this structure comes after the bind request */
+/* RPC_AUTH_NTLMSSP_REQ */
+typedef struct rpc_auth_ntlmssp_req_info
+{
+ fstring ntlmssp_str; /* "NTLMSSP" */
+ uint32 ntlmssp_ver; /* 0x0000 0001 */
+
+ uint32 unknown_0; /* 0x00b2b3 */
+ 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_REQ;
+
+/* this is TEMPORARILY coded up as a specific structure */
+/* this structure comes after the bind acknowledgement */
+/* RPC_AUTH_NTLMSSP_RESP */
+typedef struct rpc_auth_ntlmssp_resp_info
+{
+ uint8 auth_type; /* 0x0a */
+ uint8 auth_level; /* 0x06 */
+ uint8 stub_type_len; /* don't know */
+ uint8 padding; /* padding */
+
+ uint32 ptr_0; /* non-zero pointer to something */
+
+ fstring ntlmssp_str; /* "NTLMSSP" */
+ uint32 ntlmssp_ver; /* 0x0000 0002 */
+
+ uint32 unknown_1; /* 0x0000 0000 */
+ uint32 unknown_2; /* 0x00b2b3 */
+ uint32 unknown_3; /* 0x0082b1 */
+
+ uint8 data[16]; /* 0x10 bytes of something */
+
+} 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; /* 0x1 */
+ uint8 data[12];
+
+} RPC_AUTH_NTLMSSP_CHK;
+
+#endif /* _DCE_RPC_H */
+
diff --git a/source/include/rpc_lsa.h b/source/include/rpc_lsa.h
new file mode 100644
index 00000000000..8bcc4a13386
--- /dev/null
+++ b/source/include/rpc_lsa.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 _RPC_LSA_H /* _RPC_LSA_H */
+#define _RPC_LSA_H
+
+#include "rpc_misc.h"
+
+enum SID_NAME_USE
+{
+ SID_NAME_USER = 1,
+ SID_NAME_DOM_GRP = 2, /* domain group */
+ SID_NAME_WKN_GRP = 5 /* well-known group */
+};
+
+/* ntlsa pipe */
+#define LSA_CLOSE 0x00
+#define LSA_QUERYINFOPOLICY 0x07
+#define LSA_ENUMTRUSTDOM 0x0d
+#define LSA_LOOKUPNAMES 0x0e
+#define LSA_LOOKUPSIDS 0x0f
+#define LSA_OPENPOLICY 0x2c
+#define LSA_OPENSECRET 0x1C
+
+/* XXXX these are here to get a compile! */
+#define LSA_LOOKUPRIDS 0xFD
+
+#define LSA_MAX_GROUPS 32
+#define LSA_MAX_SIDS 32
+
+/* 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;
+
+
+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 sec_qos; /* 0 - security quality of service */
+
+} LSA_OBJ_ATTR;
+
+/* LSA_Q_OPEN_POL - LSA Query Open Policy */
+typedef struct lsa_q_open_pol_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_POL;
+
+/* LSA_R_OPEN_POL - response to LSA Open Policy */
+typedef struct lsa_r_open_pol_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 status; /* return code */
+
+} LSA_R_OPEN_POL;
+
+/* 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_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) */
+
+ union
+ {
+ DOM_QUERY_3 id3;
+ DOM_QUERY_5 id5;
+
+ } dom;
+
+ uint32 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 other_domain_sid;
+
+ uint32 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. */
+
+ uint32 status; /* return code */
+
+} LSA_R_CLOSE;
+
+
+#define MAX_REF_DOMAINS 10
+
+/* DOM_R_REF */
+typedef struct dom_ref_info
+{
+ uint32 undoc_buffer; /* undocumented buffer pointer. */
+ uint32 num_ref_doms_1; /* num referenced domains? */
+ uint32 buffer_dom_name; /* undocumented domain name buffer pointer. */
+ uint32 max_entries; /* 32 - max number of entries */
+ uint32 num_ref_doms_2; /* 4 - num referenced domains? */
+
+ UNIHDR2 hdr_dom_name; /* domain name unicode string header */
+ UNIHDR2 hdr_ref_dom[MAX_REF_DOMAINS]; /* referenced domain unicode string headers */
+
+ UNISTR uni_dom_name; /* domain name unicode string */
+ DOM_SID2 ref_dom[MAX_REF_DOMAINS]; /* referenced domain SIDs */
+
+} DOM_R_REF;
+
+/* LSA_TRANS_NAME - translated name */
+typedef struct lsa_trans_name_info
+{
+ uint32 sid_name_use; /* value is 5 for a well-known group; 2 for a domain group; 1 for a user... */
+
+ UNIHDR hdr_name;
+ UNISTR2 uni_name;
+
+ uint32 domain_idx;
+
+} 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;
+
+ uint32 ptr_name[MAX_LOOKUP_SIDS]; /* translated name pointers */
+ LSA_TRANS_NAME name [MAX_LOOKUP_SIDS]; /* translated names */
+
+} 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[MAX_LOOKUP_SIDS]; /* domain SID pointers to be looked up. */
+ DOM_SID2 sid [MAX_LOOKUP_SIDS]; /* 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_hnd; /* 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
+{
+ DOM_R_REF *dom_ref; /* domain reference info */
+ LSA_TRANS_NAME_ENUM *names;
+ uint32 mapped_count;
+
+ uint32 status; /* return code */
+
+} LSA_R_LOOKUP_SIDS;
+
+/* DOM_NAME - XXXX not sure about this structure */
+typedef struct dom_name_info
+{
+ uint32 uni_str_len;
+ UNISTR str;
+
+} DOM_NAME;
+
+
+#define UNKNOWN_LEN 1
+
+/* LSA_Q_LOOKUP_RIDS - LSA Lookup RIDs */
+typedef struct lsa_q_lookup_rids
+{
+ POLICY_HND pol_hnd; /* policy handle */
+ uint32 num_entries;
+ uint32 num_entries2;
+ uint32 buffer_dom_sid; /* undocumented domain SID buffer pointer */
+ uint32 buffer_dom_name; /* undocumented domain name buffer pointer */
+ DOM_NAME lookup_name[MAX_LOOKUP_SIDS]; /* names to be looked up */
+ uint8 undoc[UNKNOWN_LEN]; /* completely undocumented bytes of unknown length */
+
+} LSA_Q_LOOKUP_RIDS;
+
+/* LSA_R_LOOKUP_RIDS - response to LSA Lookup RIDs by name */
+typedef struct lsa_r_lookup_rids
+{
+ DOM_R_REF dom_ref; /* domain reference info */
+
+ uint32 num_entries;
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+
+ uint32 num_entries2;
+ DOM_RID2 dom_rid[MAX_LOOKUP_SIDS]; /* domain RIDs being looked up */
+
+ uint32 num_entries3;
+
+ uint32 status; /* return code */
+
+} LSA_R_LOOKUP_RIDS;
+
+
+#endif /* _RPC_LSA_H */
+
diff --git a/source/include/rpc_misc.h b/source/include/rpc_misc.h
new file mode 100644
index 00000000000..c03471ebfce
--- /dev/null
+++ b/source/include/rpc_misc.h
@@ -0,0 +1,278 @@
+/*
+ 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_MISC_H /* _RPC_MISC_H */
+#define _RPC_MISC_H
+
+
+#include "rpc_dce.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;
+
+#define MAXSUBAUTHS 15 /* max sub authorities in a SID */
+
+/* DOM_SID - security id */
+typedef struct sid_info
+{
+ uint8 sid_rev_num; /* SID revision number */
+ uint8 num_auths; /* number of sub-authorities */
+ uint8 id_auth[6]; /* Identifier Authority */
+ /*
+ * Note that the values in these uint32's are in *native* byteorder,
+ * not neccessarily little-endian...... JRA.
+ */
+ uint32 sub_auths[MAXSUBAUTHS]; /* pointer to sub-authorities. */
+
+} DOM_SID;
+
+/* 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_max_len;
+ uint16 str_str_len;
+ uint32 buffer; /* non-zero */
+
+} STRHDR;
+
+/* UNIHDR - unicode string header */
+typedef struct unihdr_info
+{
+ uint16 uni_max_len;
+ uint16 uni_str_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
+
+/* UNISTR - unicode string size and buffer */
+typedef struct unistr_info
+{
+ uint16 buffer[MAX_UNISTRLEN]; /* unicode characters. ***MUST*** be null-terminated */
+
+} UNISTR;
+
+/* UNINOTSTR2 - 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 uninotstr2_info
+{
+ uint32 uni_max_len;
+ uint32 undoc;
+ uint32 uni_buf_len;
+ uint16 buffer[MAX_UNISTRLEN]; /* unicode characters. **NOT** necessarily null-terminated */
+
+} UNINOTSTR2;
+
+/* UNISTR2 - unicode string size (in uint16 unicode chars) and buffer */
+typedef struct unistr2_info
+{
+ uint32 uni_max_len;
+ uint32 undoc;
+ uint32 uni_str_len;
+ uint16 buffer[MAX_UNISTRLEN]; /* unicode characters. **NOT** necessarily null-terminated */
+
+} 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[MAX_STRINGLEN]; /* uint8 characters. **NOT** necessarily null-terminated */
+
+} STRING2;
+
+
+/* DOM_RID2 - domain RID structure for ntlsa pipe */
+typedef struct domrid2_info
+{
+ uint32 type; /* value is 5 */
+ uint32 undoc; /* value is non-zero */
+ uint32 rid;
+ uint32 rid_idx; /* don't know what this is */
+
+} 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 */
+
+} 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_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;
+
+#define POL_HND_SIZE 20
+
+/* POLICY_HND */
+typedef struct lsa_policy_info
+{
+ uint8 data[POL_HND_SIZE]; /* policy handle */
+
+} POLICY_HND;
+
+#endif /* _RPC_MISC_H */
+
diff --git a/source/include/rpc_netlogon.h b/source/include/rpc_netlogon.h
new file mode 100644
index 00000000000..ca8231fc5bc
--- /dev/null
+++ b/source/include/rpc_netlogon.h
@@ -0,0 +1,375 @@
+/*
+ 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_REQCHAL 0x04
+#define NET_SRVPWSET 0x06
+#define NET_SAMLOGON 0x02
+#define NET_SAMLOGOFF 0x03
+#define NET_AUTH2 0x0f
+#define NET_LOGON_CTRL2 0x0e
+#define NET_TRUST_DOM_LIST 0x13
+
+/* Secure Channel types. used in NetrServerAuthenticate negotiation */
+#define SEC_CHAN_WKSTA 2
+#define SEC_CHAN_DOMAIN 4
+
+
+/* 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_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 */
+
+ 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[LSA_MAX_GROUPS]; /* group info */
+
+ UNISTR2 uni_logon_srv; /* logon server unicode string */
+ UNISTR2 uni_logon_dom; /* logon domain unicode string */
+
+ DOM_SID2 dom_sid; /* domain SID */
+ DOM_SID2 other_sids[LSA_MAX_SIDS]; /* undocumented - domain SIDs */
+
+} NET_USER_INFO_3;
+
+
+/********************************************************
+ Logon Control 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;
+
+/* 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 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;
+
+ uint32 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 */
+
+ uint32 function_code; /* 0x31 */
+
+} 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];
+
+ uint32 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 */
+
+ uint32 status; /* return code */
+
+} NET_R_REQ_CHAL;
+
+
+
+/* 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 */
+
+ uint32 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 */
+
+ uint32 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;
+ uint16 validation_level;
+
+} DOM_SAM_INFO;
+
+/* NET_Q_SAM_LOGON */
+typedef struct net_q_sam_logon_info
+{
+ DOM_SAM_INFO sam_id;
+
+} 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? */
+
+ uint32 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. */
+
+ uint32 status; /* return code */
+
+} NET_R_SAM_LOGOFF;
+
+
+#endif /* _RPC_NETLOGON_H */
+
diff --git a/source/include/rpc_reg.h b/source/include/rpc_reg.h
new file mode 100644
index 00000000000..28d11710cdf
--- /dev/null
+++ b/source/include/rpc_reg.h
@@ -0,0 +1,141 @@
+/*
+ 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_POLICY 0x02
+#define REG_OPEN_ENTRY 0x0f
+#define REG_INFO 0x11
+#define REG_CLOSE 0x05
+
+/* REG_Q_OPEN_POLICY */
+typedef struct q_reg_open_policy_info
+{
+ uint32 ptr;
+ uint16 unknown_0; /* 0x5da0 - 16 bit unknown */
+ uint32 level; /* 0x0000 0001 - 32 bit unknown */
+ uint16 unknown_1; /* 0x0200 - 16 bit unknown */
+
+} REG_Q_OPEN_POLICY;
+
+/* REG_R_OPEN_POLICY */
+typedef struct r_reg_open_policy_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 status; /* return status */
+
+} REG_R_OPEN_POLICY;
+
+
+/* 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. */
+
+ uint32 status; /* return code */
+
+} REG_R_CLOSE;
+
+
+/* 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 ptr1; /* pointer */
+ NTTIME time; /* current time? */
+ uint8 major_version1; /* 0x4 - os major version? */
+ uint8 minor_version1; /* 0x1 - os minor version? */
+ uint8 pad1[10]; /* padding - zeros */
+
+ uint32 ptr2; /* pointer */
+ uint8 major_version2; /* 0x4 - os major version? */
+ uint8 minor_version2; /* 0x1 - os minor version? */
+ uint8 pad2[2]; /* padding - zeros */
+
+ uint32 ptr3; /* pointer */
+ uint32 unknown; /* 0x0000 0000 */
+
+} REG_Q_INFO;
+
+/* REG_R_INFO */
+typedef struct r_reg_info_info
+{
+ uint32 ptr1; /* buffer pointer */
+ uint32 level; /* 0x1 - info level? */
+
+ uint32 ptr_type; /* pointer to o/s type */
+ UNINOTSTR2 uni_type; /* unicode string o/s type - "LanmanNT" */
+
+ uint32 ptr2; /* pointer to unknown_0 */
+ uint32 unknown_0; /* 0x12 */
+
+ uint32 ptr3; /* pointer to unknown_1 */
+ uint32 unknown_1; /* 0x12 */
+
+ uint32 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 */
+ uint16 unknown_1; /* 16 bit unknown - 0x0000 */
+ uint16 unknown_2; /* 16 bit unknown - 0x0200 */
+
+} REG_Q_OPEN_ENTRY;
+
+
+
+/* REG_R_OPEN_ENTRY */
+typedef struct r_reg_open_entry_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 status; /* return status */
+
+} REG_R_OPEN_ENTRY;
+
+
+
+#endif /* _RPC_REG_H */
+
diff --git a/source/include/rpc_samr.h b/source/include/rpc_samr.h
new file mode 100644
index 00000000000..bcce64b6bea
--- /dev/null
+++ b/source/include/rpc_samr.h
@@ -0,0 +1,1023 @@
+/*
+ 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_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:
+
+SamrAddMemberToAlias
+SamrAddMemberToGroup
+SamrAddMultipleMembersToAlias
+SamrChangePasswordUser
+x SamrCloseHandle
+x SamrConnect
+SamrCreateAliasInDomain
+SamrCreateGroupInDomain
+SamrCreateUserInDomain
+SamrDeleteAlias
+SamrDeleteGroup
+SamrDeleteUser
+x SamrEnumerateAliasesInDomain
+SamrEnumerateDomainsInSamServer
+x SamrEnumerateGroupsInDomain
+x SamrEnumerateUsersInDomain
+SamrGetUserDomainPasswordInformation
+SamrLookupDomainInSamServer
+? SamrLookupIdsInDomain
+x SamrLookupNamesInDomain
+x SamrOpenAlias
+x SamrOpenDomain
+SamrOpenGroup
+x SamrOpenUser
+x SamrQueryDisplayInformation
+x SamrQueryInformationAlias
+SamrQueryInformationDomain
+? SamrQueryInformationUser
+SamrQuerySecurityObject
+SamrRemoveMemberFromAlias
+SamrRemoveMemberFromForiegnDomain
+SamrRemoveMemberFromGroup
+SamrRemoveMultipleMembersFromAlias
+SamrSetInformationAlias
+SamrSetInformationDomain
+SamrSetInformationGroup
+SamrSetInformationUser
+SamrSetMemberAttributesOfGroup
+SamrSetSecurityObject
+SamrShutdownSamServer
+SamrTestPrivateFunctionsDomain
+SamrTestPrivateFunctionsUser
+
+********************************************************************/
+
+#define SAMR_CLOSE_HND 0x01
+#define SAMR_OPEN_DOMAIN 0x07
+#define SAMR_UNKNOWN_8 0x08
+#define SAMR_LOOKUP_IDS 0x10
+#define SAMR_LOOKUP_NAMES 0x11
+#define SAMR_UNKNOWN_3 0x03
+#define SAMR_QUERY_DISPINFO 0x28
+#define SAMR_OPEN_USER 0x22
+#define SAMR_QUERY_USERINFO 0x24
+#define SAMR_QUERY_USERGROUPS 0x27
+#define SAMR_UNKNOWN_12 0x12
+#define SAMR_UNKNOWN_21 0x21
+#define SAMR_UNKNOWN_32 0x32
+#define SAMR_UNKNOWN_34 0x34
+#define SAMR_CONNECT 0x39
+#define SAMR_OPEN_ALIAS 0x1b
+#define SAMR_QUERY_ALIASINFO 0x1c
+#define SAMR_ENUM_DOM_USERS 0x0d
+#define SAMR_ENUM_DOM_ALIASES 0x0f
+#define SAMR_ENUM_DOM_GROUPS 0x30
+
+
+typedef struct logon_hours_info
+{
+ uint32 len; /* normally 21 bytes */
+ uint8 hours[32];
+
+} LOGON_HRS;
+
+/* 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 */
+
+ uint16 acb_info; /* account info (ACB_xxxx bit-mask) */
+ /* uint8 pad[2] */
+
+ 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_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 rid_group;
+
+} 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 */
+ uint32 status; /* return status */
+
+} SAMR_R_CLOSE_HND;
+
+
+/****************************************************************************
+SAMR_Q_UNKNOWN_3 - info level 4. returns SIDs.
+*****************************************************************************/
+
+/* SAMR_Q_UNKNOWN_3 - probably get domain info... */
+typedef struct q_samr_unknown_3_info
+{
+ POLICY_HND user_pol; /* policy handle */
+ uint16 switch_value; /* 0x0000 0004 */
+ /* uint8 pad[2] */
+
+} SAMR_Q_UNKNOWN_3;
+
+/* DOM_SID3 example:
+ 0x14 0x035b 0x0002 S-1-1
+ 0x18 0x07ff 0x000f S-1-5-20-DOMAIN_ALIAS_RID_ADMINS
+ 0x18 0x07ff 0x000f S-1-5-20-DOMAIN_ALIAS_RID_ACCOUNT_OPS
+ 0x24 0x0044 0x0002 S-1-5-21-nnn-nnn-nnn-0x03f1
+ */
+
+/* DOM_SID3 example:
+ 0x24 0x0044 0x0002 S-1-5-21-nnn-nnn-nnn-0x03ee
+ 0x18 0x07ff 0x000f S-1-5-20-DOMAIN_ALIAS_RID_ADMINS
+ 0x14 0x035b 0x0002 S-1-1
+ */
+
+/* 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;
+
+
+#define MAX_SAM_SIDS 15
+
+/* SAM_SID_STUFF */
+typedef struct sid_stuff_info
+{
+ uint16 unknown_2; /* 0x0001 */
+ uint16 unknown_3; /* 0x8004 */
+
+ uint8 padding1[8];
+
+ uint32 unknown_4; /* 0x0000 0014 */
+ uint32 unknown_5; /* 0x0000 0014 */
+
+ uint16 unknown_6; /* 0x0002 */
+ uint16 unknown_7; /* 0x5800 */
+
+ uint32 num_sids;
+
+ uint16 padding2;
+
+ DOM_SID3 sid[MAX_SAM_SIDS];
+
+} SAM_SID_STUFF;
+
+/* SAMR_R_UNKNOWN_3 - probably an open */
+typedef struct r_samr_unknown_3_info
+{
+ uint32 ptr_0;
+ uint32 sid_stuff_len0;
+
+ uint32 ptr_1;
+ uint32 sid_stuff_len1;
+
+ SAM_SID_STUFF sid_stuff;
+
+ uint32 status; /* return status */
+
+} SAMR_R_UNKNOWN_3;
+
+
+/****************************************************************************
+SAMR_Q_UNKNOWN_8 - probably a query on domain group info.
+*****************************************************************************/
+
+/* SAMR_Q_UNKNOWN_8 - */
+typedef struct q_samr_unknown_8_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint16 switch_value; /* 0x0002 */
+
+} SAMR_Q_UNKNOWN_8;
+
+typedef struct sam_unkown_info_2_info
+{
+ uint32 unknown_0; /* 0x0000 0000 */
+ uint32 unknown_1; /* 0x0000 0000 */
+ uint32 unknown_2; /* 0x8000 0000 */
+ uint32 unknown_3; /* 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 unknown_4; /* 0x0000 0099 */
+ uint32 unknown_5; /* 0x0000 0000 */
+
+ uint32 unknown_6 ; /* 0x0000 0001 */
+ uint32 unknown_7 ; /* 0x0000 0003 */
+ uint32 unknown_8 ; /* 0x0000 0001 */
+ uint32 unknown_9 ; /* 0x0000 0008 */
+ uint32 unknown_10; /* 0x0000 0003 */
+
+ uint8 padding[16]; /* 16 bytes zeros */
+
+ UNISTR2 uni_domain; /* domain name unicode string */
+ UNISTR2 uni_server; /* server name unicode string */
+
+} SAM_UNK_INFO_2;
+
+
+typedef struct sam_unknown_ctr_info
+{
+ union
+ {
+ SAM_UNK_INFO_2 inf2;
+
+ } info;
+
+} SAM_UNK_CTR;
+
+
+/* SAMR_R_UNKNOWN_8 - */
+typedef struct r_samr_unknown_8_info
+{
+ uint32 ptr_1;
+ uint16 switch_value; /* same as in query */
+
+ SAM_UNK_CTR *ctr;
+
+ uint32 status; /* return status */
+
+} SAMR_R_UNKNOWN_8;
+
+
+/****************************************************************************
+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 connect_pol; /* policy handle */
+ uint32 rid; /* 0x2000 0000; 0x0000 0211; 0x0000 0280; 0x0000 0200 - a RID? */
+ 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 */
+ uint32 status; /* return status */
+
+} SAMR_R_OPEN_DOMAIN;
+
+
+#define MAX_SAM_ENTRIES 250
+
+typedef struct samr_entry_info
+{
+ uint32 rid;
+ UNIHDR hdr_name;
+
+} SAM_ENTRY;
+
+/* SAMR_Q_ENUM_DOM_USERS - SAM rids and names */
+typedef struct q_samr_enum_dom_users_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint16 req_num_entries; /* number of values (0 indicates unlimited?) */
+ uint16 unknown_0; /* enumeration context? */
+ 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
+{
+ uint16 total_num_entries; /* number of entries that match without the acb mask */
+ uint16 unknown_0; /* same as unknown_0 (enum context?) in request */
+ uint32 ptr_entries1; /* actual number of entries to follow, having masked some out */
+
+ uint32 num_entries2;
+ uint32 ptr_entries2;
+
+ uint32 num_entries3;
+
+ SAM_ENTRY sam[MAX_SAM_ENTRIES];
+ UNISTR2 uni_acct_name[MAX_SAM_ENTRIES];
+
+ uint32 num_entries4;
+
+ uint32 status;
+
+} SAMR_R_ENUM_DOM_USERS;
+
+
+typedef struct samr_entry_info3
+{
+ uint32 grp_idx;
+
+ uint32 rid_grp;
+ uint32 attr;
+
+ 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;
+
+/* SAMR_Q_ENUM_DOM_GROUPS - SAM rids and names */
+typedef struct q_samr_enum_dom_groups_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ /* these are possibly an enumeration context handle... */
+ uint16 switch_level; /* 0x0003 */
+ uint16 unknown_0; /* 0x0000 */
+ uint32 start_idx; /* presumably the start enumeration index */
+ uint32 unknown_1; /* 0x0000 07d0 */
+
+ uint32 max_size; /* 0x0000 7fff */
+
+} SAMR_Q_ENUM_DOM_GROUPS;
+
+
+/* SAMR_R_ENUM_DOM_GROUPS - SAM rids and names */
+typedef struct r_samr_enum_dom_groups_info
+{
+ uint32 unknown_0; /* 0x0000 0492 or 0x0000 00be */
+ uint32 unknown_1; /* 0x0000 049a or 0x0000 00be */
+ uint32 switch_level; /* 0x0000 0003 */
+
+ uint32 num_entries;
+ uint32 ptr_entries;
+
+ uint32 num_entries2;
+
+ SAM_ENTRY3 sam[MAX_SAM_ENTRIES];
+ SAM_STR3 str[MAX_SAM_ENTRIES];
+
+ uint32 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 unknown_0; /* 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 num_entries;
+ uint32 ptr_entries;
+
+ uint32 num_entries2;
+ uint32 ptr_entries2;
+
+ uint32 num_entries3;
+
+ SAM_ENTRY sam[MAX_SAM_ENTRIES];
+ UNISTR2 uni_grp_name[MAX_SAM_ENTRIES];
+
+ uint32 num_entries4;
+
+ uint32 status;
+
+} SAMR_R_ENUM_DOM_ALIASES;
+
+
+
+/* SAMR_Q_QUERY_DISPINFO - SAM rids, names and descriptions */
+typedef struct q_samr_query_disp_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint16 switch_level; /* 0x0001 and 0x0002 seen */
+ uint16 unknown_0; /* 0x0000 and 0x2000 seen */
+ uint32 start_idx; /* presumably the start enumeration index */
+ uint32 unknown_1; /* 0x0000 07d0, 0x0000 0400 and 0x0000 0200 seen */
+
+ uint32 max_size; /* 0x0000 7fff, 0x0000 7ffe and 0x0000 3fff seen*/
+
+} SAMR_Q_QUERY_DISPINFO;
+
+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
+{
+ uint32 num_entries;
+ uint32 ptr_entries;
+ uint32 num_entries2;
+
+ SAM_ENTRY1 sam[MAX_SAM_ENTRIES];
+ SAM_STR1 str[MAX_SAM_ENTRIES];
+
+
+} SAM_INFO_1;
+
+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
+{
+ uint32 num_entries;
+ uint32 ptr_entries;
+ uint32 num_entries2;
+
+ SAM_ENTRY2 sam[MAX_SAM_ENTRIES];
+ SAM_STR2 str[MAX_SAM_ENTRIES];
+
+} SAM_INFO_2;
+
+typedef struct sam_info_ctr_info
+{
+ union
+ {
+ SAM_INFO_1 *info1; /* server info */
+ SAM_INFO_2 *info2; /* user info */
+ void *info; /* allows assignment without typecasting, */
+
+ } sam;
+
+} SAM_INFO_CTR;
+
+/* SAMR_R_QUERY_DISPINFO - SAM rids, names and descriptions */
+typedef struct r_samr_query_dispinfo_info
+{
+ uint32 unknown_0; /* container length? 0x0000 0492 or 0x0000 00be */
+ uint32 unknown_1; /* container length? 0x0000 049a or 0x0000 00be */
+ uint16 switch_level; /* 0x0001 or 0x0002 */
+ /*uint8 pad[2] */
+
+ SAM_INFO_CTR *ctr;
+
+ uint32 status;
+
+} SAMR_R_QUERY_DISPINFO;
+
+
+
+/* SAMR_Q_QUERY_ALIASINFO - SAM Alias Info */
+typedef struct q_samr_enum_alias_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint16 switch_level; /* 0x0003 seen */
+
+} SAMR_Q_QUERY_ALIASINFO;
+
+typedef struct samr_alias_info3
+{
+ UNIHDR hdr_acct_desc;
+ UNISTR2 uni_acct_desc;
+
+} ALIAS_INFO3;
+
+/* SAMR_R_QUERY_ALIASINFO - SAM rids, names and descriptions */
+typedef struct r_samr_query_aliasinfo_info
+{
+ uint32 ptr;
+ uint16 switch_value; /* 0x0003 */
+ /* uint8[2] padding */
+
+ union
+ {
+ ALIAS_INFO3 info3;
+
+ } alias;
+
+ uint32 status;
+
+} SAMR_R_QUERY_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 */
+
+ uint32 status; /* return status */
+
+} SAMR_R_QUERY_USERGROUPS;
+
+
+/* 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 */
+ uint16 switch_value; /* 0x0015, 0x0011 or 0x0010 - same as in query */
+ /* uint8[2] padding. */
+
+ union
+ {
+ SAM_USER_INFO_10 *id10; /* auth-level 0x10 */
+ SAM_USER_INFO_11 *id11; /* auth-level 0x11 */
+ SAM_USER_INFO_21 *id21; /* auth-level 21 */
+ void* id; /* to make typecasting easy */
+
+ } info;
+
+ uint32 status; /* return status */
+
+} SAMR_R_QUERY_USERINFO;
+
+
+/****************************************************************************
+SAMR_Q_LOOKUP_IDS - 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_LOOKUP_IDS */
+typedef struct q_samr_lookup_ids_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[MAX_LOOKUP_SIDS]; /* pointers to sids to be looked up */
+ DOM_SID2 sid [MAX_LOOKUP_SIDS]; /* sids to be looked up. */
+
+} SAMR_Q_LOOKUP_IDS;
+
+
+/* SAMR_R_LOOKUP_IDS */
+typedef struct r_samr_lookup_ids_info
+{
+ uint32 num_entries;
+ uint32 ptr; /* undocumented buffer pointer */
+
+ uint32 num_entries2;
+ uint32 rid[MAX_LOOKUP_SIDS]; /* domain RIDs being looked up */
+
+ uint32 status; /* return code */
+
+} SAMR_R_LOOKUP_IDS;
+
+
+/****************************************************************************
+SAMR_Q_LOOKUP_NAMES - do a conversion from SID 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_LOOKUP_NAMES */
+typedef struct q_samr_lookup_names_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 num_rids1; /* number of rids being looked up */
+ uint32 rid; /* 0x0000 03e8 - RID of the server doing the query? */
+ uint32 ptr; /* 0x0000 0000 - 32 bit unknown */
+ uint32 num_rids2; /* number of rids being looked up */
+
+ UNIHDR hdr_user_name[MAX_LOOKUP_SIDS]; /* unicode account name header */
+ UNISTR2 uni_user_name[MAX_LOOKUP_SIDS]; /* unicode account name string */
+
+} SAMR_Q_LOOKUP_NAMES;
+
+
+/* SAMR_R_LOOKUP_NAMES */
+typedef struct r_samr_lookup_names_info
+{
+ uint32 num_entries;
+ uint32 undoc_buffer; /* undocumented buffer pointer */
+
+ uint32 num_entries2;
+ DOM_RID3 dom_rid[MAX_LOOKUP_SIDS]; /* domain RIDs being looked up */
+
+ uint32 num_entries3;
+
+ uint32 status; /* return code */
+
+} SAMR_R_LOOKUP_NAMES;
+
+
+/****************************************************************************
+SAMR_Q_UNKNOWN_12 - do a conversion from RID groups to something.
+
+called to resolve domain RID groups.
+*****************************************************************************/
+/* SAMR_Q_UNKNOWN_12 */
+typedef struct q_samr_unknown_12_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 num_gids1; /* number of rids being looked up */
+ uint32 rid; /* 0x0000 03e8 - RID of the server doing the query? */
+ uint32 ptr; /* 0x0000 0000 - 32 bit unknown */
+ uint32 num_gids2; /* number of rids being looked up */
+
+ uint32 gid[MAX_LOOKUP_SIDS]; /* domain RIDs being looked up */
+
+} SAMR_Q_UNKNOWN_12;
+
+
+/****************************************************************************
+SAMR_R_UNKNOWN_12 - do a conversion from group RID to names
+
+*****************************************************************************/
+/* SAMR_R_UNKNOWN_12 */
+typedef struct r_samr_unknown_12_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ uint32 num_aliases1; /* number of aliases being looked up */
+ uint32 ptr_aliases; /* pointer to aliases */
+ uint32 num_aliases2; /* number of aliases being looked up */
+
+ UNIHDR hdr_als_name[MAX_LOOKUP_SIDS]; /* unicode account name header */
+ UNISTR2 uni_als_name[MAX_LOOKUP_SIDS]; /* unicode account name string */
+
+ uint32 num_als_usrs1; /* number of users in aliases being looked up */
+ uint32 ptr_als_usrs; /* pointer to users in aliases */
+ uint32 num_als_usrs2; /* number of users in aliases being looked up */
+
+ uint32 num_als_usrs[MAX_LOOKUP_SIDS]; /* number of users per group */
+
+ uint32 status;
+
+} SAMR_R_UNKNOWN_12;
+
+
+/* SAMR_Q_OPEN_USER - probably an open */
+typedef struct q_samr_open_user_info
+{
+ POLICY_HND domain_pol; /* policy handle */
+ uint32 unknown_0; /* 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 */
+ uint32 status; /* return status */
+
+} SAMR_R_OPEN_USER;
+
+
+/* SAMR_Q_UNKNOWN_13 - probably an open alias in domain */
+typedef struct q_samr_unknown_13_info
+{
+ POLICY_HND alias_pol; /* policy handle */
+
+ uint16 unknown_1; /* 16 bit unknown - 0x0200 */
+ uint16 unknown_2; /* 16 bit unknown - 0x0000 */
+
+} SAMR_Q_UNKNOWN_13;
+
+
+/* SAMR_Q_UNKNOWN_21 - probably an open group in domain */
+typedef struct q_samr_unknown_21_info
+{
+ POLICY_HND group_pol; /* policy handle */
+
+ uint16 unknown_1; /* 16 bit unknown - 0x0477 */
+ uint16 unknown_2; /* 16 bit unknown - 0x0000 */
+
+} SAMR_Q_UNKNOWN_21;
+
+
+/* SAMR_Q_UNKNOWN_32 - probably a "create SAM entry" */
+typedef struct q_samr_unknown_32_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ UNIHDR hdr_mach_acct; /* unicode machine account name header */
+ UNISTR2 uni_mach_acct; /* unicode machine account name */
+
+ uint32 acct_ctrl; /* 32 bit ACB_XXXX */
+ uint16 unknown_1; /* 16 bit unknown - 0x00B0 */
+ uint16 unknown_2; /* 16 bit unknown - 0xe005 */
+
+} SAMR_Q_UNKNOWN_32;
+
+
+/* SAMR_R_UNKNOWN_32 - probably a "create SAM entry" */
+typedef struct r_samr_unknown_32_info
+{
+ POLICY_HND pol; /* policy handle */
+
+ /* rid4.unknown - fail: 0030 success: 0x03ff */
+ DOM_RID4 rid4; /* rid and attributes */
+
+ uint32 status; /* return status - fail: 0xC000 0099: user exists */
+
+} SAMR_R_UNKNOWN_32;
+
+
+/* SAMR_Q_OPEN_ALIAS - probably an open */
+typedef struct q_samr_open_alias_info
+{
+ uint32 unknown_0; /* 0x0000 0008 */
+ uint32 rid_alias; /* rid */
+
+} SAMR_Q_OPEN_ALIAS;
+
+
+/* SAMR_R_OPEN_ALIAS - probably an open */
+typedef struct r_samr_open_alias_info
+{
+ POLICY_HND pol; /* policy handle */
+ uint32 status; /* return status */
+
+} SAMR_R_OPEN_ALIAS;
+
+
+/* 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 unknown_0; /* 32 bit unknown */
+
+} SAMR_Q_CONNECT;
+
+
+/* SAMR_R_CONNECT - probably an open */
+typedef struct r_samr_connect_info
+{
+ POLICY_HND connect_pol; /* policy handle */
+ uint32 status; /* return status */
+
+} SAMR_R_CONNECT;
+
+/* SAMR_Q_UNKNOWN_38 */
+typedef struct q_samr_unknown_38
+{
+ uint32 ptr;
+ UNIHDR hdr_srv_name;
+ UNISTR2 uni_srv_name;
+
+} SAMR_Q_UNKNOWN_38;
+
+/* SAMR_R_UNKNOWN_38 */
+typedef struct r_samr_unknown_38
+{
+ LOOKUP_LEVEL level; /* 0x0006 */
+ uint32 ptr_0; /* 0x0000 0000 */
+ uint32 status;
+
+} SAMR_R_UNKNOWN_38;
+
+/* 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_server; /* server name unicode header */
+ UNISTR2 uni_server; /* 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_1; /* seems to always contain 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
+{
+ uint32 result; /* 0 == OK, C000006A (NT_STATUS_WRONG_PASSWORD) */
+
+} SAMR_R_CHGPASSWD_USER;
+
+#endif /* _RPC_SAMR_H */
+
diff --git a/source/include/rpc_srvsvc.h b/source/include/rpc_srvsvc.h
new file mode 100644
index 00000000000..afcef4e1685
--- /dev/null
+++ b/source/include/rpc_srvsvc.h
@@ -0,0 +1,576 @@
+/*
+ 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_NETSHAREENUM 0x0f
+#define SRV_NET_SRV_GET_INFO 0x15
+#define SRV_NET_SRV_SET_INFO 0x16
+#define SRV_NET_REMOTE_TOD 0x1c
+
+/* 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;
+
+ uint32 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;
+
+ uint32 status; /* return status */
+
+} SRV_R_NET_CONN_ENUM;
+
+/* oops - this is going to take up a *massive* amount of stack. */
+/* the UNISTR2s already have 1024 uint16 chars in them... */
+#define MAX_SHARE_ENTRIES 128
+
+/* 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
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_share_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+
+ SH_INFO_1 info_1 [MAX_SHARE_ENTRIES]; /* share entry pointers */
+ SH_INFO_1_STR info_1_str[MAX_SHARE_ENTRIES]; /* share entry strings */
+
+} 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
+{
+ uint32 num_entries_read; /* EntriesRead */
+ uint32 ptr_share_info; /* Buffer */
+ uint32 num_entries_read2; /* EntriesRead */
+
+ SH_INFO_2 info_2 [MAX_SHARE_ENTRIES]; /* share entry pointers */
+ SH_INFO_2_STR info_2_str[MAX_SHARE_ENTRIES]; /* share entry strings */
+
+} SRV_SHARE_INFO_2;
+
+/* SRV_SHARE_INFO_CTR */
+typedef struct srv_share_info_1_info
+{
+ uint32 switch_value; /* switch value */
+ uint32 ptr_share_ctr; /* pointer to share info union */
+ union
+ {
+ SRV_SHARE_INFO_1 info1; /* share info level 1 */
+ SRV_SHARE_INFO_2 info2; /* share info level 2 */
+
+ } 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 */
+
+ uint32 share_level; /* share level */
+
+ 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
+{
+ uint32 share_level; /* share level */
+ SRV_SHARE_INFO_CTR *ctr; /* share info container */
+
+ uint32 total_entries; /* total number of entries */
+ ENUM_HND enum_hnd;
+
+ uint32 status; /* return status */
+
+} SRV_R_NET_SHARE_ENUM;
+
+/* 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;
+
+ uint32 status; /* return status */
+
+} SRV_R_NET_FILE_ENUM;
+
+/* 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;
+
+} 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;
+
+ uint32 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 */
+
+ uint32 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;
+
+ uint32 status; /* return status */
+
+} SRV_R_NET_REMOTE_TOD;
+
+
+#endif /* _RPC_SRVSVC_H */
+
diff --git a/source/include/rpc_wkssvc.h b/source/include/rpc_wkssvc.h
new file mode 100644
index 00000000000..1483997acb3
--- /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 */
+
+ uint32 status; /* return status */
+
+} WKS_R_QUERY_INFO;
+
+
+#endif /* _RPC_WKS_H */
+
diff --git a/source/include/rpcclient.h b/source/include/rpcclient.h
new file mode 100644
index 00000000000..1065b7c1599
--- /dev/null
+++ b/source/include/rpcclient.h
@@ -0,0 +1,120 @@
+/*
+ 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 _RPCCLIENT_H
+#define _RPCCLIENT_H
+
+struct tar_client_info
+{
+ int blocksize;
+ BOOL inc;
+ BOOL reset;
+ BOOL excl;
+ char type;
+ int attrib;
+ char **cliplist;
+ int clipn;
+ int tp;
+ int num_files;
+ int buf_size;
+ int bytes_written;
+ char *buf;
+ int handle;
+ int print_mode;
+ char *file_mode;
+};
+
+struct nt_client_info
+{
+ /************* \PIPE\NETLOGON stuff ******************/
+
+ fstring mach_acct;
+
+ uint8 sess_key[16];
+ DOM_CRED clnt_cred;
+ DOM_CRED rtn_cred;
+
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 user_info3;
+
+ /************** \PIPE\lsarpc stuff ********************/
+
+ POLICY_HND lsa_info_pol;
+
+ /* domain member */
+ fstring level3_dom;
+ fstring level3_sid;
+
+ /* domain controller */
+ fstring level5_dom;
+ fstring level5_sid;
+
+ /************** \PIPE\samr stuff ********************/
+
+ POLICY_HND samr_pol_connect;
+ POLICY_HND samr_pol_open_domain;
+ POLICY_HND samr_pol_open_user;
+
+ struct acct_info *sam;
+ int num_sam_entries;
+};
+
+struct client_info
+{
+ struct in_addr dest_ip;
+ fstring dest_host;
+ fstring query_host;
+ uint8 name_type;
+
+ fstring myhostname;
+ fstring mach_acct;
+
+ pstring cur_dir;
+ pstring base_dir;
+ pstring file_sel;
+
+ fstring service;
+ fstring share;
+ fstring svc_type;
+
+ time_t newer_than;
+ int archive_level;
+ int dir_total;
+ int put_total_time_ms;
+ int put_total_size;
+ int get_total_time_ms;
+ int get_total_size;
+ int print_mode;
+ BOOL translation;
+ BOOL recurse_dir;
+ BOOL prompt;
+ BOOL lowercase;
+ BOOL abort_mget;
+
+ struct tar_client_info tar;
+ struct nt_client_info dom;
+};
+
+enum action_type {ACTION_HEADER, ACTION_ENUMERATE, ACTION_FOOTER};
+
+#endif /* _RPCCLIENT_H */
diff --git a/source/include/smb.h b/source/include/smb.h
index b7faffa9e92..f42951ec596 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-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
@@ -21,77 +24,137 @@
#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
-#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 IS_BITS_SET_ALL(var,bit) (((var)&(bit))==(bit))
+#define IS_BITS_SET_SOME(var,bit) (((var)&(bit))!=0)
+#define IS_BITS_CLR_ALL(var,bit) (((var)&(~(bit)))==0)
+
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
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.
-*/
+/* limiting size of ipc replies */
+#define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
-/* afs/stds.h defines int16 and int32 */
-#ifndef AFS_AUTH
-typedef short int16;
-typedef int int32;
-#endif
+#define SIZEOFWORD 2
-#ifndef uint16
-typedef unsigned short uint16;
+#ifndef DEF_CREATE_MASK
+#define DEF_CREATE_MASK (0755)
#endif
-#ifndef uint32
-typedef unsigned int uint32;
+#ifndef PRINTCAP_NAME
+#define PRINTCAP_NAME "/etc/printcap"
#endif
-#define SIZEOFWORD 2
+/* how long to wait for secondary SMB packets (milli-seconds) */
+#define SMB_SECONDARY_WAIT (60*1000)
+
+/* -------------------------------------------------------------------------- **
+ * 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 */
+#ifdef HAVE_STDARG_H
+int Debug1( char *, ... )
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+BOOL dbgtext( char *, ... )
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+;
+#else
+int Debug1();
+BOOL dbgtext();
+#endif
-#ifndef DEF_CREATE_MASK
-#define DEF_CREATE_MASK (0755)
+/* 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
-#ifndef DEFAULT_PIPE_TIMEOUT
-#define DEFAULT_PIPE_TIMEOUT 10000000 /* Ten seconds */
+#ifdef HAVE_FUNCTION_MACRO
+#define FUNCTION_MACRO (__FUNCTION__)
+#else
+#define FUNCTION_MACRO ("")
#endif
-/* debugging code */
-#ifndef SYSLOG
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))?(Debug1 body):0)
+/* Debugging macros.
+ * DEBUGLVL() - If level is <= the system-wide DEBUGLEVEL then generate a
+ * header using the default macros for file, line, and
+ * function name.
+ * Returns True if the debug level was <= DEBUGLEVEL.
+ * Example usage:
+ * if( DEBUGLVL( 2 ) )
+ * dbgtext( "Some text.\n" );
+ * DEGUG() - Good old DEBUG(). Each call to DEBUG() will generate a new
+ * header *unless* the previous debug output was unterminated
+ * (i.e., no '\n'). See debug.c:dbghdr() for more info.
+ * Example usage:
+ * DEBUG( 2, ("Some text.\n") );
+ * DEBUGADD() - If level <= DEBUGLEVEL, then the text is appended to the
+ * current message (i.e., no header).
+ * Usage:
+ * DEBUGADD( 2, ("Some additional text.\n") );
+ */
+#define DEBUGLVL( level ) \
+ ( (DEBUGLEVEL >= (level)) \
+ && dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) ) )
+
+#if 0
+
+#define DEBUG( level, body ) \
+ ( ( DEBUGLEVEL >= (level) \
+ && dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) ) ) \
+ ? (void)(dbgtext body) : (void)0 )
+
+#define DEBUGADD( level, body ) \
+ ( (DEBUGLEVEL >= (level)) ? (void)(dbgtext body) : (void)0 )
+
#else
-EXTERN int syslog_level;
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? \
- (syslog_level = (level), Debug1 body):0)
+#define DEBUG( level, body ) \
+ (void)( (DEBUGLEVEL >= (level)) \
+ && (dbghdr( level, FILE_MACRO, FUNCTION_MACRO, (__LINE__) )) \
+ && (dbgtext body) )
+
+#define DEBUGADD( level, body ) \
+ (void)( (DEBUGLEVEL >= (level)) && (dbgtext body) )
+
#endif
+/* End Debugging code section.
+ * -------------------------------------------------------------------------- **
+ */
+
+/* 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 DIR_STRUCT_SIZE 43
/* these define all the command types recognised by the server - there
@@ -108,6 +171,13 @@ implemented */
#define aDIR (1L<<4)
#define aARCH (1L<<5)
+/* 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)
+
/* deny modes */
#define DENY_DOS 0
#define DENY_ALL 1
@@ -117,12 +187,13 @@ implemented */
#define DENY_FCB 7
/* 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) */
+#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 $) */
-/* SMB X/Open error codes for the ERRdos error class */
+/* 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 */
@@ -141,15 +212,19 @@ implemented */
#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 ERRfilexists 80 /* File in operation already exists */
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRunknownlevel 124
#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 ERRbaddirectory 267 /* Invalid directory name in a path. */
#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 ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */
+#define ERROR_NOTIFY_ENUM_DIR 1022 /* Buffer too small to return change notify. */
#define ERRunknownipc 2142
@@ -214,55 +289,161 @@ implemented */
typedef char pstring[1024];
typedef char fstring[128];
-typedef fstring string;
-typedef struct
+/* pipe strings */
+#define PIPE_LANMAN "\\PIPE\\LANMAN"
+#define PIPE_SRVSVC "\\PIPE\\srvsvc"
+#define PIPE_SAMR "\\PIPE\\samr"
+#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"
+
+
+/* 64 bit time (100usec) since ????? - cifs6.txt, section 3.5, page 30 */
+typedef struct nttime_info
{
- 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 low;
+ uint32 high;
+
+} NTTIME;
+
+/* 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
+
+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 */
+
+ char *smb_name; /* username string */
+ char *full_name; /* user's full name string */
+ char *home_dir; /* home directory string */
+ char *dir_drive; /* home directory drive string */
+ char *logon_script; /* logon script string */
+ char *profile_path; /* profile path string */
+ char *acct_desc ; /* user description string */
+ char *workstations; /* login from workstations string */
+ char *unknown_str ; /* don't know what this is, yet. */
+ char *munged_dial ; /* munged path name and dial-back tel number */
+
+ int smb_userid; /* this is actually the unix uid_t */
+ int smb_grpid; /* this is actually the unix gid_t */
+ uint32 user_rid; /* Primary User ID */
+ uint32 group_rid; /* Primary Group ID */
+
+ unsigned char *smb_passwd; /* Null if no password */
+ unsigned char *smb_nt_passwd; /* 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 */
+};
+
+struct smb_passwd
+{
+ int smb_userid; /* this is actually the unix uid_t */
+ char *smb_name; /* username string */
+
+ unsigned char *smb_passwd; /* Null if no password */
+ 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 */
+};
+
+
+struct sam_disp_info
+{
+ uint32 user_rid; /* Primary User ID */
+ char *smb_name; /* username string */
+ char *full_name; /* user's full name string */
+};
+
+/* DOM_CHAL - challenge info */
+typedef struct chal_info
+{
+ uchar data[8]; /* credentials */
+} DOM_CHAL;
+
+/* 32 bit time (sec) since 01jan1970 - cifs6.txt, section 3.5, page 30 */
+typedef struct time_info
+{
+ uint32 time;
+} UTIME;
+
+/* DOM_CREDs - timestamped client or server credentials */
+typedef struct cred_info
+{
+ DOM_CHAL challenge; /* credentials */
+ UTIME timestamp; /* credential time-stamp */
+} DOM_CRED;
/* 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
+/*
+ * Structure used to indirect fd's from the files_struct.
+ * Needed as POSIX locking is based on file and process, not
+ * file descriptor and process.
+ */
+
+typedef struct file_fd_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;
-} files_struct;
+ struct file_fd_struct *next, *prev;
+ uint16 ref_count;
+ uint16 uid_cache_count;
+ uid_t uid_users_cache[10];
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ int fd;
+ int fd_readonly;
+ int fd_writeonly;
+ int real_open_flags;
+} file_fd_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;
@@ -271,43 +452,115 @@ struct uid_cache {
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;
+ char *name;
+ BOOL is_wild;
+} name_compare_entry;
+
+typedef struct connection_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;
+ char *user; /* name of user who *opened* this connection */
+ int uid; /* uid of user who *opened* this connection */
+ int gid; /* gid of user who *opened* this connection */
+
+ 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;
+
+ 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;
+struct current_user
+{
+ connection_struct *conn;
+ int vuid;
+ int uid, gid;
+ int ngroups;
+ GID_T *groups;
+};
+
+typedef struct files_struct
+{
+ struct files_struct *next, *prev;
+ int fnum;
+ connection_struct *conn;
+ file_fd_struct *fd_ptr;
+ SMB_OFF_T pos;
+ SMB_OFF_T size;
+ mode_t mode;
+ int vuid;
+ char *mmap_ptr;
+ SMB_OFF_T mmap_size;
+ write_bmpx_struct *wbmpx_ptr;
+ struct timeval open_time;
+ BOOL open;
+ BOOL can_lock;
+ BOOL can_read;
+ BOOL can_write;
+ BOOL share_mode;
+ BOOL print_file;
+ BOOL modified;
+ BOOL granted_oplock;
+ BOOL sent_oplock_break;
+ BOOL is_directory;
+ BOOL delete_on_close;
+ char *fsp_name;
+} files_struct;
+
+/* 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) */
+};
typedef struct
{
int uid; /* uid of a validated user */
int gid; /* gid of a validated user */
- fstring name; /* name of a validated user */
+
+ fstring requested_name; /* user name from the client */
+ fstring name; /* unix user name of a validated user */
+ fstring real_name; /* to store real name from password file - simeon */
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 :-( */
+ int n_groups;
+ GID_T *groups;
+
+ int n_sids;
+ int *sids;
+
+ /* per-user authentication information on NT RPCs */
+ struct dcinfo dc;
+
} user_struct;
@@ -332,8 +585,130 @@ typedef struct
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 */
+};
+
+
+/* used for network interfaces */
+struct interface
+{
+ struct interface *next;
+ struct in_addr ip;
+ struct in_addr bcast;
+ struct in_addr nmask;
+};
+
+/* struct returned by get_share_modes */
+typedef struct
+{
+ int pid;
+ uint16 op_port;
+ uint16 op_type;
+ int share_mode;
+ struct timeval time;
+} share_mode_entry;
+
+
+/* each implementation of the share mode code needs
+ to support the following operations */
+struct share_ops {
+ BOOL (*stop_mgmt)(void);
+ BOOL (*lock_entry)(connection_struct *, SMB_DEV_T , SMB_INO_T , int *);
+ BOOL (*unlock_entry)(connection_struct *, SMB_DEV_T , SMB_INO_T , int );
+ int (*get_entries)(connection_struct *, int , SMB_DEV_T , SMB_INO_T , share_mode_entry **);
+ void (*del_entry)(int , files_struct *);
+ BOOL (*set_entry)(int, files_struct *, uint16 , uint16 );
+ BOOL (*remove_oplock)(files_struct *, int);
+ int (*forall)(void (*)(share_mode_entry *, char *));
+ void (*status)(FILE *);
+};
+
+/* each implementation of the shared memory code needs
+ to support the following operations */
+struct shmem_ops {
+ BOOL (*shm_close)( void );
+ int (*shm_alloc)(int );
+ BOOL (*shm_free)(int );
+ int (*get_userdef_off)(void);
+ void *(*offset2addr)(int );
+ int (*addr2offset)(void *addr);
+ BOOL (*lock_hash_entry)(unsigned int);
+ BOOL (*unlock_hash_entry)( unsigned int );
+ BOOL (*get_usage)(int *,int *,int *);
+ unsigned (*hash_size)(void);
+};
+
+/*
+ * Each implementation of the password database code needs
+ * to support the following operations.
+ */
+
+struct passdb_ops {
+ /*
+ * Password database ops.
+ */
+ void *(*startsmbpwent)(BOOL);
+ void (*endsmbpwent)(void *);
+ SMB_BIG_UINT (*getsmbpwpos)(void *);
+ BOOL (*setsmbpwpos)(void *, SMB_BIG_UINT);
+
+ /*
+ * smb password database query functions.
+ */
+ struct smb_passwd *(*getsmbpwnam)(char *);
+ struct smb_passwd *(*getsmbpwuid)(uid_t);
+ struct smb_passwd *(*getsmbpwent)(void *);
+
+ /*
+ * smb password database modification functions.
+ */
+ BOOL (*add_smbpwd_entry)(struct smb_passwd *);
+ BOOL (*mod_smbpwd_entry)(struct smb_passwd *, BOOL);
+
+ /*
+ * Functions that manupulate a struct sam_passwd.
+ */
+ struct sam_passwd *(*getsam21pwent)(void *);
+
+ /*
+ * sam password database query functions.
+ */
+ struct sam_passwd *(*getsam21pwnam)(char *);
+ struct sam_passwd *(*getsam21pwuid)(uid_t);
+ struct sam_passwd *(*getsam21pwrid)(uint32);
+
+ /*
+ * sam password database modification functions.
+ */
+ BOOL (*add_sam21pwd_entry)(struct sam_passwd *);
+ BOOL (*mod_sam21pwd_entry)(struct sam_passwd *, BOOL);
+
+ /*
+ * sam query display info functions.
+ */
+ struct sam_disp_info *(*getsamdispnam)(char *);
+ struct sam_disp_info *(*getsamdisprid)(uint32);
+ struct sam_disp_info *(*getsamdispent)(void *);
+
+#if 0
+ /*
+ * password checking functions
+ */
+ struct smb_passwd *(*smb_password_chal )(char *username, char lm_pass[24], char nt_pass[24], char chal[8]);
+ struct smb_passwd *(*smb_password_check )(char *username, char lm_hash[16], char nt_hash[16]);
+ struct passwd *(*unix_password_check)(char *username, char *pass, int pass_len);
+#endif
+};
/* this is used for smbstatus */
+
struct connect_record
{
int magic;
@@ -347,50 +722,120 @@ struct connect_record
time_t start;
};
+/* This is used by smbclient to send it to a smbfs mount point */
+struct connection_options {
+ int protocol;
+ /* Connection-Options */
+ uint32 max_xmit;
+ uint16 server_uid;
+ uint16 tid;
+ /* The following are LANMAN 1.0 options */
+ uint16 sec_mode;
+ uint16 max_mux;
+ uint16 max_vcs;
+ uint16 rawmode;
+ uint32 sesskey;
+ /* The following are NT LM 0.12 options */
+ uint32 maxraw;
+ uint32 capabilities;
+ uint16 serverzone;
+};
+
+/* the following are used by loadparm for option lists */
+typedef enum
+{
+ P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
+ 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;
+
+struct enum_list {
+ int value;
+ char *name;
+};
+
+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;
+ } def;
+};
+
+struct bitmap {
+ uint32 *b;
+ int n;
+};
+
+#define FLAG_BASIC 1 /* fundamental options */
+#define FLAG_HIDE 2 /* options that should be hidden in SWAT */
+#define FLAG_PRINT 4 /* printing options */
+#define FLAG_GLOBAL 8 /* local options that should be globally settable in SWAT */
+#define FLAG_DEPRECATED 16 /* options that should no longer be used */
-#define LOCKING_VERSION 2
+#ifndef LOCKING_VERSION
+#define LOCKING_VERSION 4
+#endif /* LOCKING_VERSION */
/* 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)) \
+#define OPEN_FSP(fsp) ((fsp) && (fsp)->open && !(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(ERRDOS,ERRbadfid))
-#define CHECK_READ(fnum) if (!Files[fnum].can_read) \
+#define CHECK_READ(fsp) if (!(fsp)->can_read) \
return(ERROR(ERRDOS,ERRbadaccess))
-#define CHECK_WRITE(fnum) if (!Files[fnum].can_write) \
+#define CHECK_WRITE(fsp) if (!(fsp)->can_write) \
return(ERROR(ERRDOS,ERRbadaccess))
-#define CHECK_ERROR(fnum) if (HAS_CACHED_ERROR(fnum)) \
- return(CACHED_ERROR(fnum))
+#define CHECK_ERROR(fsp) if (HAS_CACHED_ERROR(fsp)) \
+ return(CACHED_ERROR(fsp))
/* translates a connection number into a service number */
-#define SNUM(cnum) (Connections[cnum].service)
+#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(cnum) (OPEN_CNUM(cnum) && !Connections[cnum].read_only)
+#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(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 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))
+
#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 +873,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 */
@@ -510,23 +964,38 @@ 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
/* these are the trans2 sub fields for primary requests */
#define smb_tpscnt smb_vwv0
@@ -565,302 +1034,190 @@ 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
+
+/* 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
+
+/* Generic access masks & rights. */
+#define SPECIFIC_RIGHTS_MASK 0x00FFFFL
+#define STANDARD_RIGHTS_MASK 0xFF0000L
+#define DELETE_ACCESS (1L<<16)
+#define READ_CONTROL_ACCESS (1L<<17)
+#define WRITE_DAC_ACCESS (1L<<18)
+#define WRITE_OWNER_ACCESS (1L<<19)
+#define SYNCHRONIZE_ACCESS (1L<<20)
+#define SYSTEM_SECURITY_ACCESS (1L<<24)
+
+/* 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_COMPRESSED 0x800L
+#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 0x1
+#define FILE_CASE_PRESERVED_NAMES 0x2
+#define FILE_UNICODE_ON_DISK 0x4
+#define FILE_PERISITANT_ACLS 0x8
+
+/* ChangeNotify flags. */
+#define FILE_NOTIFY_CHANGE_FILE_NAME 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
+
/* where to find the base of the SMB packet proper */
#define smb_base(buf) (((char *)(buf))+4)
-#define SUCCESS 0 /* The request was successful. */
+#define SMB_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 */
-};
-
-/* 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 *, ...);
+#ifdef HAVE_STDARG_H
+int slprintf(char *str, int n, char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 3, 4)))
+#endif
+;
#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
+int slprintf();
+#endif
+
+#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))
@@ -874,7 +1231,7 @@ char *Strstr(char *s, char *p);
#endif
#ifndef SIGNAL_CAST
-#define SIGNAL_CAST
+#define SIGNAL_CAST (RETSIGTYPE (*)(int))
#endif
#ifndef SELECT_CAST
@@ -951,27 +1308,73 @@ 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_ALTERNATE_XPORT 0x20000000
#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000
#define SV_TYPE_DOMAIN_ENUM 0x80000000
#define SV_TYPE_ALL 0xFFFFFFFF
+/* what server type are we currently - JHT Says we ARE 4.20 */
+/* this was set by JHT in liaison with Jeremy Allison early 1997 */
+/* setting to 4.20 at same time as announcing ourselves as NT Server */
+/* 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 */
+
+#define DEFAULT_MAJOR_VERSION 0x04
+#define DEFAULT_MINOR_VERSION 0x02
+
+/* 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_DFS_PATHNAMES 0x1000
+#define FLAGS2_READ_PERMIT_NO_EXECUTE 0x2000
+#define FLAGS2_32_BIT_ERROR_CODES 0x4000
+#define FLAGS2_UNICODE_STRINGS 0x8000
+
+/* 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_LARGE_READX 0x4000
/* 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};
/* 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};
+/* Remote architectures we know about. */
+enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, 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 */
/* Macros to get at offsets within smb_lkrng and smb_unlkrng
structures. We cannot define these as actual structures
@@ -981,16 +1384,19 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
#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_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(fnum) (Files[(fnum)].open && \
- Files[(fnum)].wbmpx_ptr && \
- Files[(fnum)].wbmpx_ptr->wr_discard)
+#define HAS_CACHED_ERROR(fsp) ((fsp)->open && (fsp)->wbmpx_ptr && \
+ (fsp)->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 CACHED_ERROR(fsp) cached_error_packet(inbuf,outbuf,fsp,__LINE__)
/* these are the datagram types */
#define DGRAM_DIRECT_UNIQUE 0x10
@@ -1002,5 +1408,171 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
#define ROUNDUP(x,g) (((x)+((g)-1))&~((g)-1))
-#endif
+/*
+ * 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 */
+
+/*
+ * 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;
+
+/*
+ * 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
+
+/* Oplock levels */
+#define OPLOCKLEVEL_NONE 0
+#define OPLOCKLEVEL_II 1
+
+/*
+ * Bits we test with.
+ */
+#define EXCLUSIVE_OPLOCK 1
+#define BATCH_OPLOCK 2
+
+#define CORE_OPLOCK_GRANTED (1<<5)
+#define EXTENDED_OPLOCK_GRANTED (1<<15)
+
+/*
+ * 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.
+ *
+ * Form of this is :
+ *
+ * 0 2 6 10 14 14+devsize 14+devsize+inodesize
+ * +----+--------+--------+--------+-------+--------+
+ * | cmd| pid | sec | usec | dev | inode |
+ * +----+--------+--------+--------+-------+--------+
+ */
+
+#define OPLOCK_BREAK_CMD 0x1
+#define OPLOCK_BREAK_PID_OFFSET 2
+#define OPLOCK_BREAK_SEC_OFFSET 6
+#define OPLOCK_BREAK_USEC_OFFSET 10
+#define OPLOCK_BREAK_DEV_OFFSET 14
+#define OPLOCK_BREAK_INODE_OFFSET (OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))
+#define OPLOCK_BREAK_MSG_LEN (OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T))
+
+/*
+ * Capabilities abstracted for different systems.
+ */
+
+#define KERNEL_OPLOCK_CAPABILITY 0x1
+
+#if defined(HAVE_KERNEL_OPLOCKS)
+/*
+ * Oplock break command code sent via the kernel interface.
+ *
+ * Form of this is :
+ *
+ * 0 2 2+devsize 2+devsize+inodesize
+ * +----+--------+--------+
+ * | cmd| dev | inode |
+ * +----+--------+--------+
+ */
+
+#define KERNEL_OPLOCK_BREAK_CMD 0x2
+#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_MSG_LEN (KERNEL_OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T))
+
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+#define CMD_REPLY 0x8000
+
+/* useful macros */
+
+/* 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) 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))
+
+#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))
+
+#include "ntdomain.h"
+
+/* A netbios name structure. */
+struct nmb_name {
+ char name[17];
+ char scope[64];
+ unsigned int name_type;
+};
+
+#include "client.h"
+#include "rpcclient.h"
+
+/*
+ * Size of new password account encoding string. DO NOT CHANGE.
+ */
+
+#define NEW_PW_FORMAT_SPACE_PADDED_LEN 14
+
+#endif /* _SMB_H */
+
/* _SMB_H */
diff --git a/source/include/stamp-h.in b/source/include/stamp-h.in
new file mode 100644
index 00000000000..7aae7732de7
--- /dev/null
+++ b/source/include/stamp-h.in
@@ -0,0 +1 @@
+Tue Sep 29 04:45:55 UTC 1998
diff --git a/source/include/trans2.h b/source/include/trans2.h
index cc366ccaea0..894823602ee 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
@@ -228,13 +233,6 @@ Byte offset Type name description
#define DIRLEN_GUESS (45+MAX(l1_achName,l2_achName))
-/* Function prototypes */
-
-
-int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
-
-int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
-
#endif
diff --git a/source/include/version.h b/source/include/version.h
index 9ad8b7d44b5..921701de4b2 100644
--- a/source/include/version.h
+++ b/source/include/version.h
@@ -1 +1 @@
-#define VERSION "1.9.16alpha1"
+#define VERSION "2.0.0-prealpha"
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..971f2567388
--- /dev/null
+++ b/source/internals.doc
@@ -0,0 +1,212 @@
+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 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/lib/.cvsignore b/source/lib/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/lib/.cvsignore
diff --git a/source/lib/access.c b/source/lib/access.c
index 14a84b2fb44..31f9db4e554 100644
--- a/source/lib/access.c
+++ b/source/lib/access.c
@@ -1,139 +1,142 @@
/*
-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-bugs@samba.anu.edu.au
*/
#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";
-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
-
-
-/* return true if access should be allowed to a service*/
-BOOL check_access(int snum)
+/* masked_match - match address against netnumber/netmask */
+static int masked_match(char *tok, char *slash, char *s)
{
- extern int Client;
- extern struct from_host Client_info;
- char *denyl,*allowl;
- BOOL ret = False;
-
- denyl = lp_hostsdeny(snum);
- if (denyl) denyl = strdup(denyl);
-
- allowl = lp_hostsallow(snum);
- if (allowl) allowl = strdup(allowl);
-
-
- fromhost(Client,&Client_info);
-
- if ((!denyl || *denyl==0) && (!allowl || *allowl==0))
- ret = True;
-
- 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)));
+ 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);
+}
- if (denyl) free(denyl);
- if (allowl) free(allowl);
- return(ret);
+/* string_match - match string against token */
+static int string_match(char *tok,char *s)
+{
+ int tok_len;
+ int str_len;
+ char *cut;
+
+ /* 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)));
+
+ 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(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(tok, '/')) != 0) { /* netnumber/netmask */
+ if (isdigit((int)s[0]) && masked_match(tok, cut, s))
+ return (True);
+ }
+ return (False);
}
-/* return true if access should be allowed */
-BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client)
+/* client_match - match host name and address against token */
+static int client_match(char *tok,char *item)
{
- /* 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);
+ char **client = (char **)item;
+ int match;
- return (True);
+ /*
+ * Try to match the address first. If that fails, try to match the host
+ * name if available.
+ */
+
+ if ((match = string_match(tok, client[1])) == 0)
+ if (client[0][0] != 0)
+ match = string_match(tok, client[0]);
+ 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;
+ int match = False;
/*
* jkf@soton.ac.uk -- 31 August 1994 -- Stop list_match()
@@ -153,237 +156,88 @@ static int list_match(char *list,char *item, int (*match_fn)())
for (tok = strtok(listcopy, sep); tok ; tok = strtok(NULL, sep)) {
if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
break;
- if ((match = (*match_fn) (tok, item))) /* YES or FAIL */
+ if ((match = (*match_fn) (tok, item))) /* True or FAIL */
break;
}
- /* Process exceptions to YES or FAIL matches. */
+ /* Process exceptions to True or FAIL matches. */
- if (match != NO) {
+ if (match != False) {
while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
/* VOID */ ;
- if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) {
+ if (tok == 0 || list_match((char *) 0, item, match_fn) == False) {
if (listcopy != 0) free(listcopy); /* jkf */
return (match);
}
}
if (listcopy != 0) free(listcopy); /* jkf */
- return (NO);
+ return (False);
}
-/* 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.
- */
-
- 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)
+/* return true if access should be allowed */
+BOOL allow_access(char *deny_list,char *allow_list,
+ char *cname,char *caddr)
{
- int tok_len;
- int str_len;
- char *cut;
+ char *client[2];
- /*
- * 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.
- */
+ client[0] = cname;
+ client[1] = caddr;
- 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);
+ /* 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);
}
- }
-#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);
-}
-/* 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 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);
}
-
-/* fromhost - find out what is at the other end of a socket */
-BOOL fromhost(int sock,struct from_host *f)
+/* return true if access should be allowed to a service for a socket */
+BOOL check_access(int sock, char *allow_list, char *deny_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);
- }
+ BOOL ret = False;
+
+ if (deny_list) deny_list = strdup(deny_list);
+ if (allow_list) allow_list = strdup(allow_list);
- return(True);
-}
+ if ((!deny_list || *deny_list==0) && (!allow_list || *allow_list==0)) {
+ ret = True;
+ }
-/* matchname - determine if host name matches IP address */
-static int matchname(char *remotehost,struct in_addr addr)
-{
- struct hostent *hp;
- int i;
-
- if ((hp = Get_Hostbyname(remotehost)) == 0) {
- DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
- return (Bad);
- }
+ if (!ret) {
+ if (allow_access(deny_list,allow_list,
+ client_name(sock),client_addr(sock))) {
+ DEBUG(2,("Allowed connection from %s (%s)\n",
+ client_name(sock),client_addr(sock)));
+ ret = True;
+ } else {
+ DEBUG(0,("Denied connection from %s (%s)\n",
+ client_name(sock),client_addr(sock)));
+ }
+ }
- /*
- * 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);
- }
-
- /* 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) free(deny_list);
+ if (allow_list) free(allow_list);
+ return(ret);
}
-
-
diff --git a/source/lib/bitmap.c b/source/lib/bitmap.c
new file mode 100644
index 00000000000..9ccdbb420b1
--- /dev/null
+++ b/source/lib/bitmap.c
@@ -0,0 +1,130 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* these functions provide a simple way to allocate integers from a
+ pool without repitition */
+
+
+/****************************************************************************
+allocate a bitmap of the specified size
+****************************************************************************/
+struct bitmap *bitmap_allocate(int n)
+{
+ struct bitmap *bm;
+
+ bm = (struct bitmap *)malloc(sizeof(*bm));
+ bm->n = n;
+
+ if (!bm) return NULL;
+
+ bm->b = (uint32 *)malloc(sizeof(bm->b[0])*(n+31)/32);
+ if (!bm->b) {
+ free(bm);
+ return NULL;
+ }
+
+ memset(bm->b, 0, sizeof(bm->b[0])*(n+31)/32);
+
+ return 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
+****************************************************************************/
+static 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..b016a07fd73 100644
--- a/source/lib/charcnv.c
+++ b/source/lib/charcnv.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Character set conversion Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ 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,22 +20,23 @@
*/
#include "includes.h"
+#define CTRLZ 26
extern int DEBUGLEVEL;
static char cvtbuf[1024];
-static mapsinited = 0;
+static BOOL mapsinited = 0;
static char unix2dos[256];
static char dos2unix[256];
-static void initmaps() {
+static void initmaps(void) {
int k;
for (k = 0; k < 256; k++) unix2dos[k] = k;
for (k = 0; k < 256; k++) dos2unix[k] = k;
- mapsinited = 1;
+ mapsinited = True;
}
static void update_map(char * str) {
@@ -50,77 +51,180 @@ static void update_map(char * str) {
}
}
-static void initiso() {
+static void init_iso8859_1(void) {
+ int i;
if (!mapsinited) initmaps();
- 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");
+ /* Do not map undefined characters to some accidental code */
+ for (i = 128; i < 256; i++)
+ {
+ unix2dos[i] = CTRLZ;
+ dos2unix[i] = CTRLZ;
+ }
+
+/* MSDOS Code Page 850 -> ISO-8859 */
+update_map("\240\377\241\255\242\275\243\234\244\317\245\276\246\335\247\365");
+update_map("\250\371\251\270\252\246\253\256\254\252\255\360\256\251\257\356");
+update_map("\260\370\261\361\262\375\263\374\264\357\265\346\266\364\267\372");
+update_map("\270\367\271\373\272\247\273\257\274\254\275\253\276\363\277\250");
+update_map("\300\267\301\265\302\266\303\307\304\216\305\217\306\222\307\200");
+update_map("\310\324\311\220\312\322\313\323\314\336\315\326\316\327\317\330");
+update_map("\320\321\321\245\322\343\323\340\324\342\325\345\326\231\327\236");
+update_map("\330\235\331\353\332\351\333\352\334\232\335\355\336\350\337\341");
+update_map("\340\205\341\240\342\203\343\306\344\204\345\206\346\221\347\207");
+update_map("\350\212\351\202\352\210\353\211\354\215\355\241\356\214\357\213");
+update_map("\360\320\361\244\362\225\363\242\364\223\365\344\366\224\367\366");
+update_map("\370\233\371\227\372\243\373\226\374\201\375\354\376\347\377\230");
+
+}
+
+/* Init for eastern european languages. */
+
+static void init_iso8859_2(void) {
+
+ int i;
+ if (!mapsinited) initmaps();
+
+ /* Do not map undefined characters to some accidental code */
+ for (i = 128; i < 256; i++)
+ {
+ unix2dos[i] = CTRLZ;
+ dos2unix[i] = CTRLZ;
+ }
+
+/*
+ * Tranlation table created by Petr Hubeny <psh@capitol.cz>
+ * Requires client code page = 852
+ * and character set = ISO8859-2 in smb.conf
+ */
+
+/* MSDOS Code Page 852 -> ISO-8859-2 */
+update_map("\241\244\242\364\243\235\244\317\245\225\246\227\247\365");
+update_map("\250\371\251\346\252\270\253\233\254\215\256\246\257\275");
+update_map("\261\245\262\362\263\210\264\357\265\226\266\230\267\363");
+update_map("\270\367\271\347\272\255\273\234\274\253\275\361\276\247\277\276");
+update_map("\300\350\301\265\302\266\303\306\304\216\305\221\306\217\307\200");
+update_map("\310\254\311\220\312\250\313\323\314\267\315\326\316\327\317\322");
+update_map("\320\321\321\343\322\325\323\340\324\342\325\212\326\231\327\236");
+update_map("\330\374\331\336\332\351\333\353\334\232\335\355\336\335\337\341");
+update_map("\340\352\341\240\342\203\343\307\344\204\345\222\346\206\347\207");
+update_map("\350\237\351\202\352\251\353\211\354\330\355\241\356\214\357\324");
+update_map("\360\320\361\344\362\345\363\242\364\223\365\213\366\224\367\366");
+update_map("\370\375\371\205\372\243\373\373\374\201\375\354\376\356\377\372");
+}
+
+/* Init for russian language (iso8859-5) */
+
+/* Added by Max Khon <max@iclub.nsu.ru> */
+
+static void init_iso8859_5(void)
+{
+ int i;
+ if (!mapsinited) initmaps();
+
+ /* Do not map undefined characters to some accidental code */
+ for (i = 128; i < 256; i++)
+ {
+ unix2dos[i] = CTRLZ;
+ dos2unix[i] = CTRLZ;
+ }
+
+/* MSDOS Code Page 866 -> ISO8859-5 */
+update_map("\200\260\201\261\202\262\203\263\204\264\205\265\206\266\207\267");
+update_map("\210\270\211\271\212\272\213\273\214\274\215\275\216\276\217\277");
+update_map("\220\300\221\301\222\302\223\303\224\304\225\305\226\306\227\307");
+update_map("\230\310\231\311\232\312\233\313\234\314\235\315\236\316\237\317");
+update_map("\240\320\241\321\242\322\243\323\244\324\245\325\246\326\247\327");
+update_map("\250\330\251\331\252\332\253\333\254\334\255\335\256\336\257\337");
+update_map("\340\340\341\341\342\342\343\343\344\344\345\345\346\346\347\347");
+update_map("\350\350\351\351\352\352\353\353\354\354\355\355\356\356\357\357");
+update_map("\360\241\361\361\362\244\363\364\364\247\365\367\366\256\367\376");
+update_map("\374\360\377\240");
+}
+
+/* Init for russian language (koi8) */
+
+static void init_koi8_r(void)
+{
+ if (!mapsinited) initmaps();
+
+ /* There aren't undefined characters between 128 and 255 */
+
+/* MSDOS Code Page 866 -> KOI8-R */
+update_map("\200\304\201\263\202\332\203\277\204\300\205\331\206\303\207\264");
+update_map("\210\302\211\301\212\305\213\337\214\334\215\333\216\335\217\336");
+update_map("\220\260\221\261\222\262\223\364\224\376\225\371\226\373\227\367");
+update_map("\230\363\231\362\232\377\233\365\234\370\235\375\236\372\237\366");
+update_map("\240\315\241\272\242\325\243\361\244\326\245\311\246\270\247\267");
+update_map("\250\273\251\324\252\323\253\310\254\276\255\275\256\274\257\306");
+update_map("\260\307\261\314\262\265\263\360\264\266\265\271\266\321\267\322");
+update_map("\270\313\271\317\272\320\273\312\274\330\275\327\276\316\277\374");
+update_map("\300\356\301\240\302\241\303\346\304\244\305\245\306\344\307\243");
+update_map("\310\345\311\250\312\251\313\252\314\253\315\254\316\255\317\256");
+update_map("\320\257\321\357\322\340\323\341\324\342\325\343\326\246\327\242");
+update_map("\330\354\331\353\332\247\333\350\334\355\335\351\336\347\337\352");
+update_map("\340\236\341\200\342\201\343\226\344\204\345\205\346\224\347\203");
+update_map("\350\225\351\210\352\211\353\212\354\213\355\214\356\215\357\216");
+update_map("\360\217\361\237\362\220\363\221\364\222\365\223\366\206\367\202");
+update_map("\370\234\371\233\372\207\373\230\374\235\375\231\376\227\377\232");
}
/*
* Convert unix to dos
*/
-char *
-unix2dos_format(char *str,BOOL overwrite)
+char *unix2dos_format(char *str,BOOL overwrite)
{
char *p;
char *dp;
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 (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;
+ }
}
/*
* Convert dos to unix
*/
-char *
-dos2unix_format (char *str, BOOL overwrite)
+char *dos2unix_format(char *str, BOOL overwrite)
{
char *p;
char *dp;
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;
- }
+
+ 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;
+ }
}
/*
* Interpret character set.
*/
-int
-interpret_character_set (char *str, int def)
+void interpret_character_set(char *str)
{
-
if (strequal (str, "iso8859-1")) {
- initiso();
- return def;
+ init_iso8859_1();
+ } else if (strequal (str, "iso8859-2")) {
+ init_iso8859_2();
+ } else if (strequal (str, "iso8859-5")) {
+ init_iso8859_5();
+ } else if (strequal (str, "koi8-r")) {
+ init_koi8_r();
} else {
DEBUG(0,("unrecognized character set\n"));
}
- return def;
}
diff --git a/source/lib/charset.c b/source/lib/charset.c
index ada3ef790aa..08d7726e3bf 100644
--- a/source/lib/charset.c
+++ b/source/lib/charset.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Character set 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
@@ -24,22 +24,122 @@
extern int DEBUGLEVEL;
+/*
+ * Codepage definitions.
+ */
+
+#if !defined(KANJI)
+/* lower->upper mapping for IBM Code Page 850 - MS-DOS Latin 1 */
+unsigned char cp_850[][4] = {
+/* dec col/row oct hex description */
+/* 133 08/05 205 85 a grave */
+/* 183 11/07 267 B7 A grave */ {0x85,0xB7,1,1},
+/* 160 10/00 240 A0 a acute */
+/* 181 11/05 265 B5 A acute */ {0xA0,0xB5,1,1},
+/* 131 08/03 203 83 a circumflex */
+/* 182 11/06 266 B6 A circumflex */ {0x83,0xB6,1,1},
+/* 198 12/06 306 C6 a tilde */
+/* 199 12/07 307 C7 A tilde */ {0xC6,0xC7,1,1},
+/* 132 08/04 204 84 a diaeresis */
+/* 142 08/14 216 8E A diaeresis */ {0x84,0x8E,1,1},
+/* 134 08/06 206 86 a ring */
+/* 143 08/15 217 8F A ring */ {0x86,0x8F,1,1},
+/* 145 09/01 221 91 ae diphthong */
+/* 146 09/02 222 92 AE diphthong */ {0x91,0x92,1,1},
+/* 135 08/07 207 87 c cedilla */
+/* 128 08/00 200 80 C cedilla */ {0x87,0x80,1,1},
+/* 138 08/10 212 8A e grave */
+/* 212 13/04 324 D4 E grave */ {0x8A,0xD4,1,1},
+/* 130 08/02 202 82 e acute */
+/* 144 09/00 220 90 E acute */ {0x82,0x90,1,1},
+/* 136 08/08 210 88 e circumflex */
+/* 210 13/02 322 D2 E circumflex */ {0x88,0xD2,1,1},
+/* 137 08/09 211 89 e diaeresis */
+/* 211 13/03 323 D3 E diaeresis */ {0x89,0xD3,1,1},
+/* 141 08/13 215 8D i grave */
+/* 222 13/14 336 DE I grave */ {0x8D,0xDE,1,1},
+/* 161 10/01 241 A1 i acute */
+/* 214 13/06 326 D6 I acute */ {0xA1,0xD6,1,1},
+/* 140 08/12 214 8C i circumflex */
+/* 215 13/07 327 D7 I circumflex */ {0x8C,0xD7,1,1},
+/* 139 08/11 213 8B i diaeresis */
+/* 216 13/08 330 D8 I diaeresis */ {0x8B,0xD8,1,1},
+/* 208 13/00 320 D0 Icelandic eth */
+/* 209 13/01 321 D1 Icelandic Eth */ {0xD0,0xD1,1,1},
+/* 164 10/04 244 A4 n tilde */
+/* 165 10/05 245 A5 N tilde */ {0xA4,0xA5,1,1},
+/* 149 09/05 225 95 o grave */
+/* 227 14/03 343 E3 O grave */ {0x95,0xE3,1,1},
+/* 162 10/02 242 A2 o acute */
+/* 224 14/00 340 E0 O acute */ {0xA2,0xE0,1,1},
+/* 147 09/03 223 93 o circumflex */
+/* 226 14/02 342 E2 O circumflex */ {0x93,0xE2,1,1},
+/* 228 14/04 344 E4 o tilde */
+/* 229 14/05 345 E5 O tilde */ {0xE4,0xE5,1,1},
+/* 148 09/04 224 94 o diaeresis */
+/* 153 09/09 231 99 O diaeresis */ {0x94,0x99,1,1},
+/* 155 09/11 233 9B o slash */
+/* 157 09/13 235 9D O slash */ {0x9B,0x9D,1,1},
+/* 151 09/07 227 97 u grave */
+/* 235 14/11 353 EB U grave */ {0x97,0xEB,1,1},
+/* 163 10/03 243 A3 u acute */
+/* 233 14/09 351 E9 U acute */ {0xA3,0xE9,1,1},
+/* 150 09/06 226 96 u circumflex */
+/* 234 14/10 352 EA U circumflex */ {0x96,0xEA,1,1},
+/* 129 08/01 201 81 u diaeresis */
+/* 154 09/10 232 9A U diaeresis */ {0x81,0x9A,1,1},
+/* 236 14/12 354 EC y acute */
+/* 237 14/13 355 ED Y acute */ {0xEC,0xED,1,1},
+/* 231 14/07 347 E7 Icelandic thorn */
+/* 232 14/08 350 E8 Icelandic Thorn */ {0xE7,0xE8,1,1},
+
+ {0x9C,0,0,0}, /* Pound */
+ {0,0,0,0}
+};
+#else /* KANJI */
+/* lower->upper mapping for IBM Code Page 932 - MS-DOS Japanese SJIS */
+unsigned char cp_932[][4] = {
+ {0,0,0,0}
+};
+#endif /* KANJI */
+
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;
+char *dos_char_map = xx_dos_char_map;
+char *upper_char_map = xx_upper_char_map;
+char *lower_char_map = xx_lower_char_map;
+
+/*
+ * This code has been extended to deal with ascynchronous mappings
+ * like MS-DOS Latin US (Code page 437) where things like :
+ * a acute are capitalized to 'A', but the reverse mapping
+ * must not hold true. This allows the filename case insensitive
+ * matching in do_match() to work, as the DOS/Win95/NT client
+ * uses 'A' as a mask to match against characters like a acute.
+ * This is the meaning behind the parameters that allow a
+ * mapping from lower to upper, but not upper to lower.
+ */
-static void add_dos_char(int lower, int upper)
+static void add_dos_char(int lower, BOOL map_lower_to_upper,
+ int upper, BOOL map_upper_to_lower)
{
- 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;
+ lower &= 0xff;
+ upper &= 0xff;
+ DEBUGADD( 6, ( "Adding chars 0x%x 0x%x (l->u = %s) (u->l = %s)\n",
+ lower, upper,
+ map_lower_to_upper ? "True" : "False",
+ map_upper_to_lower ? "True" : "False" ) );
+ if (lower) dos_char_map[lower] = 1;
+ if (upper) dos_char_map[upper] = 1;
+ lower_char_map[lower] = (char)lower; /* Define tolower(lower) */
+ upper_char_map[upper] = (char)upper; /* Define toupper(upper) */
if (lower && upper) {
- lower_char_map[(char)upper] = (char)lower;
- upper_char_map[(char)lower] = (char)upper;
+ if(map_upper_to_lower)
+ lower_char_map[upper] = (char)lower;
+ if(map_lower_to_upper)
+ upper_char_map[lower] = (char)upper;
}
}
@@ -50,41 +150,226 @@ 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];
+#ifdef LC_ALL
+ /* include <locale.h> in includes.h if available for OS */
+ /* we take only standard 7-bit ASCII definitions from ctype */
+ setlocale(LC_ALL,"C");
+#endif
- for (i= -128;i<=127;i++) {
- dos_char_map[(char)i] = 0;
+ for (i= 0;i<=255;i++) {
+ dos_char_map[i] = 0;
}
for (i=0;i<=127;i++) {
- if (isalnum((char)i) || strchr("._^$~!#%&-{}()@'`",(char)i))
- add_dos_char(i,0);
+ if (isalnum(i) || strchr("._^$~!#%&-{}()@'`",(char)i))
+ add_dos_char(i,False,0,False);
}
- for (i= -128;i<=127;i++) {
+ for (i=0; i<=255; 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)*/
+
+ /* Some systems have buggy isupper/islower for characters
+ above 127. Best not to rely on them. */
+ if(i < 128) {
+ if (isupper((int)c)) lower_char_map[i] = tolower(c);
+ if (islower((int)c)) upper_char_map[i] = toupper(c);
+ }
+ }
+}
+
+/****************************************************************************
+load the client codepage.
+****************************************************************************/
+
+typedef unsigned char (*codepage_p)[4];
+
+static codepage_p load_client_codepage( int client_codepage )
+{
+ pstring codepage_file_name;
+ unsigned char buf[8];
+ FILE *fp = NULL;
+ SMB_OFF_T size;
+ codepage_p cp_p = NULL;
+ SMB_STRUCT_STAT st;
+
+ DEBUG(5, ("load_client_codepage: loading codepage %d.\n", client_codepage));
+
+ if(strlen(CODEPAGEDIR) + 14 > sizeof(codepage_file_name))
+ {
+ DEBUG(0,("load_client_codepage: filename too long to load\n"));
+ return NULL;
+ }
+
+ pstrcpy(codepage_file_name, CODEPAGEDIR);
+ pstrcat(codepage_file_name, "/");
+ pstrcat(codepage_file_name, "codepage.");
+ slprintf(&codepage_file_name[strlen(codepage_file_name)],
+ sizeof(pstring)-(strlen(codepage_file_name)+1),
+ "%03d",
+ client_codepage);
+
+ if(!file_exist(codepage_file_name,&st))
+ {
+ DEBUG(0,("load_client_codepage: filename %s does not exist.\n",
+ codepage_file_name));
+ return NULL;
+ }
+
+ /* Check if it is at least big enough to hold the required
+ data. Should be 2 byte version, 2 byte codepage, 4 byte length,
+ plus zero or more bytes of data. Note that the data cannot be more
+ than 4 * MAXCODEPAGELINES bytes.
+ */
+ size = st.st_size;
+
+ if( size < CODEPAGE_HEADER_SIZE || size > (CODEPAGE_HEADER_SIZE + 4 * MAXCODEPAGELINES))
+ {
+ DEBUG(0,("load_client_codepage: file %s is an incorrect size for a \
+code page file.\n", codepage_file_name));
+ return NULL;
+ }
+
+ /* Read the first 8 bytes of the codepage file - check
+ the version number and code page number. All the data
+ is held in little endian format.
+ */
+
+ if((fp = fopen( codepage_file_name, "r")) == NULL)
+ {
+ DEBUG(0,("load_client_codepage: cannot open file %s. Error was %s\n",
+ codepage_file_name, strerror(errno)));
+ return NULL;
+ }
+
+ if(fread( buf, 1, CODEPAGE_HEADER_SIZE, fp)!=CODEPAGE_HEADER_SIZE)
+ {
+ DEBUG(0,("load_client_codepage: cannot read header from file %s. Error was %s\n",
+ codepage_file_name, strerror(errno)));
+ goto clean_and_exit;
+ }
+
+ /* Check the version value */
+ if(SVAL(buf,CODEPAGE_VERSION_OFFSET) != CODEPAGE_FILE_VERSION_ID)
+ {
+ DEBUG(0,("load_client_codepage: filename %s has incorrect version id. \
+Needed %hu, got %hu.\n",
+ codepage_file_name, (uint16)CODEPAGE_FILE_VERSION_ID,
+ SVAL(buf,CODEPAGE_VERSION_OFFSET)));
+ goto clean_and_exit;
+ }
+
+ /* Check the codepage matches */
+ if(SVAL(buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET) != (uint16)client_codepage)
+ {
+ DEBUG(0,("load_client_codepage: filename %s has incorrect codepage. \
+Needed %hu, got %hu.\n",
+ codepage_file_name, (uint16)client_codepage,
+ SVAL(buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET)));
+ goto clean_and_exit;
+ }
+
+ /* Check the length is correct. */
+ if(IVAL(buf,CODEPAGE_LENGTH_OFFSET) != (size - CODEPAGE_HEADER_SIZE))
+ {
+ DEBUG(0,("load_client_codepage: filename %s has incorrect size headers. \
+Needed %u, got %u.\n", codepage_file_name, (uint32)(size - CODEPAGE_HEADER_SIZE),
+ IVAL(buf,CODEPAGE_LENGTH_OFFSET)));
+ goto clean_and_exit;
+ }
+
+ size -= CODEPAGE_HEADER_SIZE; /* Remove header */
+
+ /* Make sure the size is a multiple of 4. */
+ if((size % 4 ) != 0)
+ {
+ DEBUG(0,("load_client_codepage: filename %s has a codepage size not a \
+multiple of 4.\n", codepage_file_name));
+ goto clean_and_exit;
+ }
+
+ /* Allocate space for the code page file and read it all in. */
+ if((cp_p = (codepage_p)malloc( size + 4 )) == NULL)
+ {
+ DEBUG(0,("load_client_codepage: malloc fail.\n"));
+ goto clean_and_exit;
+ }
+
+ if(fread( (char *)cp_p, 1, size, fp)!=size)
+ {
+ DEBUG(0,("load_client_codepage: read fail on file %s. Error was %s.\n",
+ codepage_file_name, strerror(errno)));
+ goto clean_and_exit;
+ }
+
+ /* Ensure array is correctly terminated. */
+ memset(((char *)cp_p) + size, '\0', 4);
+
+ fclose(fp);
+ return cp_p;
+
+clean_and_exit:
+
+ /* pseudo destructor :-) */
+
+ if(fp != NULL)
+ fclose(fp);
+ if(cp_p)
+ free((char *)cp_p);
+ return NULL;
}
+/****************************************************************************
+initialise the client codepage.
+****************************************************************************/
+void codepage_initialise(int client_codepage)
+{
+ int i;
+ static codepage_p cp = NULL;
+
+ if(cp != NULL)
+ {
+ DEBUG(6,
+ ("codepage_initialise: called twice - ignoring second client code page = %d\n",
+ client_codepage));
+ return;
+ }
+
+ DEBUG(6,("codepage_initialise: client code page = %d\n", client_codepage));
+
+ /*
+ * Known client codepages - these can be added to.
+ */
+ cp = load_client_codepage( client_codepage );
+
+ if(cp == NULL)
+ {
+#ifdef KANJI
+ DEBUG(6,("codepage_initialise: loading dynamic codepage file %s/codepage.%d \
+for code page %d failed. Using default client codepage 932\n",
+ CODEPAGEDIR, client_codepage, client_codepage));
+ cp = cp_932;
+ client_codepage = KANJI_CODEPAGE;
+#else /* KANJI */
+ DEBUG(6,("codepage_initialise: loading dynamic codepage file %s/codepage.%d \
+for code page %d failed. Using default client codepage 850\n",
+ CODEPAGEDIR, client_codepage, client_codepage));
+ cp = cp_850;
+ client_codepage = MSDOS_LATIN_1_CODEPAGE;
+#endif /* KANJI */
+ }
+
+ /*
+ * Setup the function pointers for the loaded codepage.
+ */
+ initialize_multibyte_vectors( client_codepage );
+
+ if(cp)
+ {
+ for(i = 0; !((cp[i][0] == '\0') && (cp[i][1] == '\0')); i++)
+ add_dos_char(cp[i][0], (BOOL)cp[i][2], cp[i][1], (BOOL)cp[i][3]);
+ }
+}
/*******************************************************************
add characters depending on a string passed by the user
@@ -98,12 +383,12 @@ void add_char_string(char *s)
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)=='-') {
+ if (isdigit((unsigned char)*t) || (*t)=='-') {
sscanf(t,"%i:%i",&i1,&i2);
- add_dos_char(i1,i2);
+ add_dos_char(i1,True,i2,True);
} else {
sscanf(t,"%c:%c",&c1,&c2);
- add_dos_char(c1,c2);
+ add_dos_char((unsigned char)c1,True,(unsigned char)c2, True);
}
}
diff --git a/source/lib/debug.c b/source/lib/debug.c
new file mode 100644
index 00000000000..6b7b9341a3c
--- /dev/null
+++ b/source/lib/debug.c
@@ -0,0 +1,588 @@
+/*
+ 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 nul 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.
+ */
+
+FILE *dbf = NULL;
+pstring debugf = "";
+BOOL append_log = False;
+int DEBUGLEVEL = 1;
+
+
+/* -------------------------------------------------------------------------- **
+ * 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.
+ */
+
+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 int format_pos = 0;
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+#if defined(SIGUSR2)
+/* ************************************************************************** **
+ * catch a sigusr2 - decrease the debug log level.
+ * ************************************************************************** **
+ */
+void sig_usr2( int sig )
+ {
+ BlockSignals( True, SIGUSR2 );
+
+ DEBUGLEVEL--;
+ if( DEBUGLEVEL < 0 )
+ DEBUGLEVEL = 0;
+
+ DEBUG( 0, ( "Got SIGUSR2; set debug level to %d.\n", DEBUGLEVEL ) );
+
+ BlockSignals( False, SIGUSR2 );
+ CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+
+ } /* sig_usr2 */
+#endif /* SIGUSR2 */
+
+#if defined(SIGUSR1)
+/* ************************************************************************** **
+ * catch a sigusr1 - increase the debug log level.
+ * ************************************************************************** **
+ */
+void sig_usr1( int sig )
+ {
+ BlockSignals( True, SIGUSR1 );
+
+ DEBUGLEVEL++;
+
+ if( DEBUGLEVEL > 10 )
+ DEBUGLEVEL = 10;
+
+ DEBUG( 0, ( "Got SIGUSR1; set debug level to %d.\n", DEBUGLEVEL ) );
+
+ BlockSignals( False, SIGUSR1 );
+ CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+
+ } /* sig_usr1 */
+#endif /* SIGUSR1 */
+
+
+/* ************************************************************************** **
+ * get ready for syslog stuff
+ * ************************************************************************** **
+ */
+void setup_logging( char *pname, BOOL interactive )
+ {
+ if( interactive )
+ {
+ stdout_logging = True;
+ dbf = stdout;
+ }
+#ifdef WITH_SYSLOG
+ else
+ {
+ char *p = strrchr( 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
+ * ************************************************************************** **
+ */
+void reopen_logs( void )
+ {
+ pstring fname;
+
+ if( DEBUGLEVEL > 0 )
+ {
+ pstrcpy( fname, debugf );
+ if( lp_loaded() && (*lp_logfile()) )
+ pstrcpy( fname, lp_logfile() );
+
+ if( !strcsequal( fname, debugf ) || !dbf || !file_exist( debugf, NULL ) )
+ {
+ mode_t oldumask = umask( 022 );
+
+ pstrcpy( debugf, fname );
+ if( dbf )
+ (void)fclose( dbf );
+ if( append_log )
+ dbf = fopen( debugf, "a" );
+ else
+ dbf = fopen( debugf, "w" );
+ /* 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();
+ if( dbf )
+ setbuf( dbf, NULL );
+ (void)umask( oldumask );
+ }
+ }
+ else
+ {
+ if( dbf )
+ {
+ (void)fclose( dbf );
+ dbf = NULL;
+ }
+ }
+ } /* reopen_logs */
+
+/* ************************************************************************** **
+ * Force a check of the log size.
+ * ************************************************************************** **
+ */
+void force_check_log_size( void )
+ {
+ debug_count = 100;
+ } /* force_check_log_size */
+
+/* ************************************************************************** **
+ * Check to see if the log has grown to be too big.
+ * ************************************************************************** **
+ */
+static void check_log_size( void )
+ {
+ int maxlog;
+ SMB_STRUCT_STAT st;
+
+ if( debug_count++ < 100 || getuid() != 0 )
+ return;
+
+ maxlog = lp_max_log_size() * 1024;
+ if( !dbf || maxlog <= 0 )
+ return;
+
+ if( sys_fstat( fileno( dbf ), &st ) == 0 && st.st_size > maxlog )
+ {
+ (void)fclose( dbf );
+ dbf = NULL;
+ reopen_logs();
+ if( dbf && file_size( debugf ) > maxlog )
+ {
+ pstring name;
+
+ (void)fclose( dbf );
+ dbf = NULL;
+ slprintf( name, sizeof(name)-1, "%s.old", debugf );
+ (void)rename( debugf, name );
+ reopen_logs();
+ }
+ }
+ debug_count = 0;
+ } /* check_log_size */
+
+/* ************************************************************************** **
+ * Write an debug message on the debugfile.
+ * This is called by dbghdr() and format_debug_text().
+ * ************************************************************************** **
+ */
+#ifdef HAVE_STDARG_H
+ int Debug1( char *format_str, ... )
+{
+#else
+ int Debug1(va_alist)
+va_dcl
+{
+ char *format_str;
+#endif
+ va_list ap;
+ int old_errno = errno;
+
+ if( stdout_logging )
+ {
+#ifdef HAVE_STDARG_H
+ va_start( ap, format_str );
+#else
+ va_start( ap );
+ format_str = va_arg( ap, char * );
+#endif
+ (void)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 = fopen( debugf, "a" );
+ else
+ dbf = fopen( debugf, "w" );
+ (void)umask( oldumask );
+ if( dbf )
+ {
+ 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];
+
+#ifdef HAVE_STDARG_H
+ va_start( ap, format_str );
+#else
+ va_start( ap );
+ format_str = va_arg( ap, char * );
+#endif
+ vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
+ va_end( ap );
+
+ msgbuf[255] = '\0';
+ syslog( priority, "%s", msgbuf );
+ }
+#endif
+
+#ifdef WITH_SYSLOG
+ if( !lp_syslog_only() )
+#endif
+ {
+#ifdef HAVE_STDARG_H
+ va_start( ap, format_str );
+#else
+ va_start( ap );
+ format_str = va_arg( ap, char * );
+#endif
+ (void)vfprintf( dbf, format_str, ap );
+ va_end( ap );
+ (void)fflush( dbf );
+ }
+
+ check_log_size();
+
+ 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 )
+ {
+ int 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();
+ (void)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 )
+ {
+ 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()) )
+ {
+ /* Print it all out at once to prevent split syslog output. */
+ (void)Debug1( "[%s, %d] %s:%s(%d)\n",
+ timestring(), level, file, func, line );
+ }
+
+ return( True );
+ } /* dbghdr */
+
+/* ************************************************************************** **
+ * 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.
+ *
+ * ************************************************************************** **
+ */
+#ifdef HAVE_STDARG_H
+ 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 */
+
+#else
+ BOOL dbgtext( va_alist )
+ va_dcl
+ {
+ char *format_str;
+ va_list ap;
+ pstring msgbuf;
+
+ va_start( ap );
+ format_str = va_arg( ap, char * );
+ vslprintf( msgbuf, sizeof(msgbuf)-1, format_str, ap );
+ va_end( ap );
+
+ format_debug_text( msgbuf );
+
+ return( True );
+ } /* dbgtext */
+
+#endif
+
+/* ************************************************************************** */
diff --git a/source/lib/fault.c b/source/lib/fault.c
index 20c75f7876c..6effaf7d7c6 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,15 +19,11 @@
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 *);
/*******************************************************************
@@ -35,28 +31,30 @@ 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)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 +62,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/genrand.c b/source/lib/genrand.c
new file mode 100644
index 00000000000..bb1922e4f5c
--- /dev/null
+++ b/source/lib/genrand.c
@@ -0,0 +1,226 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+
+ Functions to create reasonable random numbers for crypto use.
+
+ 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 int DEBUGLEVEL;
+static uint32 counter = 0;
+
+/****************************************************************
+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 *hash)
+{
+ unsigned char buf[1011]; /* deliberate weird size */
+ unsigned char tmp_md4[16];
+ int fd, n;
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) return;
+
+ while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
+ mdfour(tmp_md4, buf, n);
+ for (n=0;n<16;n++)
+ hash[n] ^= tmp_md4[n];
+ }
+ close(fd);
+}
+
+
+
+/****************************************************************
+ Try and get a seed by looking at the atimes of files in a given
+ directory. XOR them into the buf array.
+*****************************************************************/
+
+static void do_dirrand(char *name, unsigned char *buf, int buf_len)
+{
+ void *dp = dos_opendir(name);
+ pstring fullname;
+ int len_left;
+ int fullname_len;
+ char *pos;
+
+ pstrcpy(fullname, name);
+ fullname_len = strlen(fullname);
+
+ if(fullname_len + 2 > sizeof(pstring))
+ return;
+
+ if(fullname[fullname_len] != '/') {
+ fullname[fullname_len] = '/';
+ fullname[fullname_len+1] = '\0';
+ fullname_len = strlen(fullname);
+ }
+
+ len_left = sizeof(pstring) - fullname_len - 1;
+ pos = &fullname[fullname_len];
+
+ if(dp != NULL) {
+ char *p;
+
+ while ((p = readdirname(dp))) {
+ SMB_STRUCT_STAT st;
+
+ if(strlen(p) <= len_left)
+ pstrcpy(pos, p);
+
+ if(dos_stat(fullname,&st) == 0) {
+ SIVAL(buf, ((counter * 4)%(buf_len-4)),
+ IVAL(buf,((counter * 4)%(buf_len-4))) ^ st.st_atime);
+ counter++;
+ DEBUG(10,("do_dirrand: value from file %s.\n", fullname));
+ }
+ }
+ closedir(dp);
+ }
+}
+
+/**************************************************************
+ Try and get a good random number seed. Try a number of
+ different factors. Firstly, try /dev/random and try and
+ read from this. If this fails iterate through /tmp and
+ /dev and XOR all the file timestamps. Next add in
+ a hash of the contents of /etc/shadow and the smb passwd
+ file and a combination of pid and time of day (yes I know this
+ sucks :-). Finally md4 the result.
+
+ The result goes in a 16 byte buffer passed from the caller
+**************************************************************/
+
+static uint32 do_reseed(unsigned char *md4_outbuf)
+{
+ unsigned char md4_inbuf[40];
+ BOOL got_random = False;
+ uint32 v1, v2, ret;
+ int fd;
+ struct timeval tval;
+ pid_t mypid;
+ struct passwd *pw;
+
+ memset(md4_inbuf, '\0', sizeof(md4_inbuf));
+
+ fd = open( "/dev/random", O_RDONLY);
+ if(fd >= 0) {
+ /*
+ * We can use /dev/random !
+ */
+ if(read(fd, md4_inbuf, 40) == 40) {
+ got_random = True;
+ DEBUG(10,("do_reseed: got 40 bytes from /dev/random.\n"));
+ }
+ close(fd);
+ }
+
+ if(!got_random) {
+ /*
+ * /dev/random failed - try /tmp and /dev for timestamps.
+ */
+ do_dirrand("/tmp", md4_inbuf, sizeof(md4_inbuf));
+ do_dirrand("/dev", md4_inbuf, sizeof(md4_inbuf));
+ }
+
+ /* possibly add in some secret file contents */
+ do_filehash("/etc/shadow", &md4_inbuf[0]);
+ do_filehash(lp_smb_passwd_file(), &md4_inbuf[16]);
+
+ /* add in the root encrypted password. On any system where security is taken
+ seriously this will be secret */
+ pw = getpwnam("root");
+ if (pw && pw->pw_passwd) {
+ int i;
+ unsigned char md4_tmp[16];
+ mdfour(md4_tmp, (unsigned char *)pw->pw_passwd, strlen(pw->pw_passwd));
+ for (i=0;i<16;i++)
+ md4_inbuf[8+i] ^= md4_tmp[i];
+ }
+
+ /*
+ * Finally add the counter, time of day, and pid.
+ */
+ GetTimeOfDay(&tval);
+ mypid = getpid();
+ v1 = (counter++) + mypid + tval.tv_sec;
+ v2 = (counter++) * mypid + tval.tv_usec;
+
+ SIVAL(md4_inbuf, 32, v1 ^ IVAL(md4_inbuf, 32));
+ SIVAL(md4_inbuf, 36, v2 ^ IVAL(md4_inbuf, 36));
+
+ mdfour(md4_outbuf, md4_inbuf, sizeof(md4_inbuf));
+
+ /*
+ * Return a 32 bit int created from XORing the
+ * 16 bit return buffer.
+ */
+
+ ret = IVAL(md4_outbuf, 0);
+ ret ^= IVAL(md4_outbuf, 4);
+ ret ^= IVAL(md4_outbuf, 8);
+ return (ret ^ IVAL(md4_outbuf, 12));
+}
+
+/*******************************************************************
+ Interface to the (hopefully) good crypto random number generator.
+********************************************************************/
+
+void generate_random_buffer( unsigned char *out, int len, BOOL re_seed)
+{
+ static BOOL done_reseed = False;
+ static unsigned char md4_buf[16];
+ unsigned char tmp_buf[16];
+ unsigned char *p;
+
+ if(!done_reseed || re_seed) {
+ sys_srandom(do_reseed(md4_buf));
+ done_reseed = True;
+ }
+
+ /*
+ * Generate random numbers in chunks of 64 bytes,
+ * then md4 them & copy to the output buffer.
+ * Added XOR with output from random, seeded
+ * by the original md4_buf. This is to stop the
+ * output from this function being the previous
+ * md4_buf md4'ed. The output from this function
+ * is often output onto the wire, and so it should
+ * not be possible to guess the next output from
+ * this function based on the previous output.
+ * XORing in the output from random(), seeded by
+ * the original md4 hash should stop this. JRA.
+ */
+
+ p = out;
+ while(len > 0) {
+ int i;
+ int copy_len = len > 16 ? 16 : len;
+ mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
+ memcpy(md4_buf, tmp_buf, sizeof(md4_buf));
+ /* XOR in output from random(). */
+ for(i = 0; i < 4; i++)
+ SIVAL(tmp_buf, i*4, (IVAL(tmp_buf, i*4) ^ (uint32)sys_random()));
+ memcpy(p, tmp_buf, copy_len);
+ p += copy_len;
+ len -= copy_len;
+ }
+}
diff --git a/source/lib/getsmbpass.c b/source/lib/getsmbpass.c
index 07a7dbfd9b5..7e544fa8d07 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,7 +144,7 @@ getsmbpass(char *prompt)
fclose (in);
/* Catch problematic signals */
- signal(SIGINT, SIGNAL_CAST SIG_DFL);
+ CatchSignal(SIGINT, SIGNAL_CAST SIG_DFL);
printf("\n");
return buf;
@@ -162,5 +152,5 @@ getsmbpass(char *prompt)
#else
-void getsmbpasswd_dummy() {;}
+ void getsmbpasswd_dummy(void) {;}
#endif
diff --git a/source/lib/interface.c b/source/lib/interface.c
new file mode 100644
index 00000000000..65d276021ce
--- /dev/null
+++ b/source/lib/interface.c
@@ -0,0 +1,382 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+struct in_addr ipzero;
+struct in_addr allones_ip;
+struct in_addr loopback_ip;
+static struct in_addr default_ip;
+static struct in_addr default_bcast;
+static struct in_addr default_nmask;
+static BOOL got_ip=False;
+static BOOL got_bcast=False;
+static BOOL got_nmask=False;
+
+static struct interface *local_interfaces = NULL;
+
+struct interface *last_iface;
+
+#define ALLONES ((uint32)0xFFFFFFFF)
+#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
+/****************************************************************************
+calculate the default netmask for an address
+****************************************************************************/
+static void default_netmask(struct in_addr *inm, struct in_addr *iad)
+{
+ /*
+ ** Guess a netmask based on the class of the IP address given.
+ */
+ switch((ntohl(iad->s_addr) & 0xE0000000)) {
+ case 0x00000000: /* Class A addr */
+ case 0x20000000:
+ case 0x40000000:
+ case 0x60000000:
+ inm->s_addr = htonl(0xFF000000);
+ break;
+
+ case 0x80000000: /* Class B addr */
+ case 0xA0000000:
+ inm->s_addr = htonl(0xFFFF0000);
+ break;
+
+ case 0xC0000000: /* Class C addr */
+ inm->s_addr = htonl(0xFFFFFF00);
+ break;
+
+ default: /* ??? */
+ inm->s_addr = htonl(0xFFFFFFF0);
+ }
+}
+
+
+/****************************************************************************
+ get the broadcast address for our address
+(troyer@saifr00.ateng.az.honeywell.com)
+****************************************************************************/
+static void get_broadcast(struct in_addr *if_ipaddr,
+ struct in_addr *if_bcast,
+ struct in_addr *if_nmask)
+{
+ uint32 nm;
+ short onbc;
+ short offbc;
+
+ /* get a default netmask and broadcast */
+ default_netmask(if_nmask, if_ipaddr);
+
+ get_netmask(if_ipaddr, if_nmask);
+
+ /* sanity check on the netmask */
+ nm = ntohl(if_nmask->s_addr);
+ onbc = 0;
+ offbc = 0;
+ while((onbc + offbc) < 32) {
+ if(nm & 0x80000000) {
+ onbc++;
+ if(offbc) {
+ /* already found an off bit, so mask
+ is wrong */
+ onbc = 34;
+ }
+ } else {
+ offbc++;
+ }
+ nm <<= 1;
+ }
+ if ((onbc < 8)||(onbc == 34)) {
+ DEBUG(0,("Impossible netmask %s - using defaults\n",
+ inet_ntoa(*if_nmask)));
+ default_netmask(if_nmask, if_ipaddr);
+ }
+
+ /* 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 */
+ if_bcast->s_addr = MKBCADDR(if_ipaddr->s_addr, if_nmask->s_addr);
+
+ DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
+}
+
+
+
+/****************************************************************************
+load a list of network interfaces
+****************************************************************************/
+static void interpret_interfaces(char *s, struct interface **interfaces,
+ char *description)
+{
+ char *ptr;
+ fstring token;
+ struct interface *iface;
+ struct in_addr ip;
+
+ ptr = s;
+ ipzero = *interpret_addr2("0.0.0.0");
+ allones_ip = *interpret_addr2("255.255.255.255");
+ loopback_ip = *interpret_addr2("127.0.0.1");
+
+ while (next_token(&ptr,token,NULL,sizeof(token))) {
+ /* parse it into an IP address/netmasklength pair */
+ char *p = strchr(token,'/');
+ if (p) *p++ = 0;
+
+ ip = *interpret_addr2(token);
+
+ /* maybe we already have it listed */
+ {
+ struct interface *i;
+ for (i=(*interfaces);i;i=i->next)
+ if (ip_equal(ip,i->ip)) break;
+ if (i) continue;
+ }
+
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ iface->ip = ip;
+
+ if (p) {
+ if (strlen(p) > 2)
+ iface->nmask = *interpret_addr2(p);
+ else
+ iface->nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
+ } else {
+ default_netmask(&iface->nmask,&iface->ip);
+ }
+ iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
+ iface->next = NULL;
+
+ if (!(*interfaces)) {
+ (*interfaces) = iface;
+ } else {
+ last_iface->next = iface;
+ }
+ last_iface = iface;
+ DEBUG(2,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
+ DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
+ DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
+ }
+
+ if (*interfaces) return;
+
+ /* setup a default interface */
+ iface = (struct interface *)malloc(sizeof(*iface));
+ if (!iface) return;
+
+ iface->next = NULL;
+
+ if (got_ip) {
+ iface->ip = default_ip;
+ } else {
+ get_myname(NULL,&iface->ip);
+ }
+
+ if (got_bcast) {
+ iface->bcast = default_bcast;
+ } else {
+ get_broadcast(&iface->ip,&iface->bcast,&iface->nmask);
+ }
+
+ if (got_nmask) {
+ iface->nmask = default_nmask;
+ iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
+ }
+
+ if (iface->bcast.s_addr != MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr)) {
+ DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip)));
+ }
+
+ iface->next = NULL;
+ (*interfaces) = last_iface = 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)));
+}
+
+
+/****************************************************************************
+load the remote and local interfaces
+****************************************************************************/
+void load_interfaces(void)
+{
+ /* add the machine's interfaces to local interface structure*/
+ interpret_interfaces(lp_interfaces(), &local_interfaces,"interface");
+}
+
+
+/****************************************************************************
+ override the defaults
+ **************************************************************************/
+void iface_set_default(char *ip,char *bcast,char *nmask)
+{
+ if (ip) {
+ got_ip = True;
+ default_ip = *interpret_addr2(ip);
+ }
+
+ if (bcast) {
+ got_bcast = True;
+ default_bcast = *interpret_addr2(bcast);
+ }
+
+ if (nmask) {
+ got_nmask = True;
+ default_nmask = *interpret_addr2(nmask);
+ }
+}
+
+
+/****************************************************************************
+ 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;
+}
+
+/****************************************************************************
+Try and find an interface that matches an ip. If we cannot, return NULL
+ **************************************************************************/
+static struct interface *iface_find(struct in_addr ip)
+{
+ struct interface *i;
+ if (zero_ip(ip)) return local_interfaces;
+
+ for (i=local_interfaces;i;i=i->next)
+ if (same_net(i->ip,ip,i->nmask)) return i;
+
+ 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);
+ return(i ? &i->bcast : &local_interfaces->bcast);
+}
+
+struct in_addr *iface_ip(struct in_addr ip)
+{
+ struct interface *i = iface_find(ip);
+ return(i ? &i->ip : &local_interfaces->ip);
+}
+
+
+
diff --git a/source/lib/kanji.c b/source/lib/kanji.c
index 0af476eb157..04eecb54375 100644
--- a/source/lib/kanji.c
+++ b/source/lib/kanji.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Kanji Extensions
- Copyright (C) Andrew Tridgell 1992-1994
+ 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
@@ -23,28 +23,76 @@
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;
+/*
+ * Function pointers that get overridden when multi-byte code pages
+ * are loaded.
+ */
+
+char *(*multibyte_strchr)(char *, int ) = (char *(*)(char *, int )) strchr;
+char *(*multibyte_strrchr)(char *, int ) = (char *(*)(char *, int )) strrchr;
+char *(*multibyte_strstr)(char *, char *) = (char *(*)(char *, char *)) strstr;
+char *(*multibyte_strtok)(char *, char *) = (char *(*)(char *, char *)) strtok;
+
+/*
+ * Kanji is treated differently here due to historical accident of
+ * it being the first non-English codepage added to Samba.
+ * The define 'KANJI' is being overloaded to mean 'use kanji codepage
+ * by default' and also 'this is the filename-to-disk conversion
+ * method to use'. This really should be removed and all control
+ * over this left in the smb.conf parameters 'client codepage'
+ * and 'coding system'.
+ */
+
+#ifndef KANJI
+
+/*
+ * Set the default conversion to be the functions in
+ * charcnv.c.
+ */
+
+static int skip_non_multibyte_char(char);
+static BOOL not_multibyte_char_1(char);
+
+char *(*_dos_to_unix)(char *, BOOL) = dos2unix_format;
+char *(*_unix_to_dos)(char *, BOOL) = unix2dos_format;
+int (*_skip_multibyte_char)(char) = skip_non_multibyte_char;
+BOOL (*is_multibyte_char_1)(char) = not_multibyte_char_1;
+
+#else /* KANJI */
+
+/*
+ * Set the default conversion to be the function
+ * sj_to_sj in this file.
+ */
+
+static char *sj_to_sj(char *from, BOOL overwrite);
+static int skip_kanji_multibyte_char(char);
+static BOOL is_kanji_multibyte_char_1(char);
+
+char *(*_dos_to_unix)(char *, BOOL) = sj_to_sj;
+char *(*_unix_to_dos)(char *, BOOL) = sj_to_sj;
+int (*_skip_multibyte_char)(char) = skip_kanji_multibyte_char;
+int (*is_multibyte_char_1)(char) = is_kanji_multibyte_char_1;
+
+#endif /* KANJI */
/* jis si/so sequence */
-char jis_kso = JIS_KSO;
-char jis_ksi = JIS_KSI;
-char hex_tag = HEXTAG;
+static char jis_kso = JIS_KSO;
+static char jis_ksi = JIS_KSI;
+static char hex_tag = HEXTAG;
/*******************************************************************
SHIFT JIS functions
********************************************************************/
/*******************************************************************
search token from S1 separated any char of S2
- S1 contain SHIFT JIS chars.
+ S1 contains SHIFT JIS chars.
********************************************************************/
-char *
-sj_strtok (char *s1, const char *s2)
+static char *sj_strtok(char *s1, char *s2)
{
static char *s = NULL;
char *q;
@@ -81,12 +129,11 @@ sj_strtok (char *s1, const char *s2)
/*******************************************************************
search string S2 from S1
- S1 contain SHIFT JIS chars.
+ S1 contains SHIFT JIS chars.
********************************************************************/
-char *
-sj_strstr (const char *s1, const char *s2)
+static char *sj_strstr(char *s1, char *s2)
{
- register int len = strlen ((char *) s2);
+ int len = strlen ((char *) s2);
if (!*s2)
return (char *) s1;
for (;*s1;) {
@@ -105,10 +152,9 @@ sj_strstr (const char *s1, const char *s2)
/*******************************************************************
Search char C from beginning of S.
- S contain SHIFT JIS chars.
+ S contains SHIFT JIS chars.
********************************************************************/
-char *
-sj_strchr (const char *s, int c)
+static char *sj_strchr (char *s, int c)
{
for (; *s; ) {
if (*s == c)
@@ -124,12 +170,11 @@ sj_strchr (const char *s, int c)
/*******************************************************************
Search char C end of S.
- S contain SHIFT JIS chars.
+ S contains SHIFT JIS chars.
********************************************************************/
-char *
-sj_strrchr (const char *s, int c)
+static char *sj_strrchr(char *s, int c)
{
- register char *q;
+ char *q;
for (q = 0; *s; ) {
if (*s == c) {
@@ -145,6 +190,184 @@ sj_strrchr (const char *s, int c)
}
/*******************************************************************
+ Kanji multibyte char skip function.
+*******************************************************************/
+
+static int skip_kanji_multibyte_char(char c)
+{
+ if(is_shift_jis(c)) {
+ return 2;
+ } else if (is_kana(c)) {
+ return 1;
+ }
+ return 0;
+}
+
+/*******************************************************************
+ Kanji multibyte char identification.
+*******************************************************************/
+
+static BOOL is_kanji_multibyte_char_1(char c)
+{
+ return is_shift_jis(c);
+}
+
+/*******************************************************************
+ The following functions are the only ones needed to do multibyte
+ support for Hangul, Big5 and Simplified Chinese. Most of the
+ real work for these codepages is done in the generic multibyte
+ functions. The only reason these functions are needed at all
+ is that the is_xxx(c) calls are really preprocessor macros.
+********************************************************************/
+
+/*******************************************************************
+ Hangul (Korean - code page 949) function.
+********************************************************************/
+
+static BOOL hangul_is_multibyte_char_1(char c)
+{
+ return is_hangul(c);
+}
+
+/*******************************************************************
+ Big5 Traditional Chinese (code page 950) function.
+********************************************************************/
+
+static BOOL big5_is_multibyte_char_1(char c)
+{
+ return is_big5_c1(c);
+}
+
+/*******************************************************************
+ Simplified Chinese (code page 936) function.
+********************************************************************/
+
+static BOOL simpch_is_multibyte_char_1(char c)
+{
+ return is_simpch_c1(c);
+}
+
+/*******************************************************************
+ Generic multibyte functions - used by Hangul, Big5 and Simplified
+ Chinese codepages.
+********************************************************************/
+
+/*******************************************************************
+ search token from S1 separated any char of S2
+ S1 contains generic multibyte chars.
+********************************************************************/
+
+static char *generic_multibyte_strtok(char *s1, char *s2)
+{
+ static char *s = NULL;
+ char *q;
+ if (!s1) {
+ if (!s) {
+ return NULL;
+ }
+ s1 = s;
+ }
+ for (q = s1; *s1; ) {
+ if ((*is_multibyte_char_1)(*s1)) {
+ s1 += 2;
+ } 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 contains generic multibyte chars.
+********************************************************************/
+
+static char *generic_multibyte_strstr(char *s1, char *s2)
+{
+ 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_multibyte_char_1)(*s1)) {
+ s1 += 2;
+ } else {
+ s1++;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************
+ Search char C from beginning of S.
+ S contains generic multibyte chars.
+********************************************************************/
+
+static char *generic_multibyte_strchr(char *s, int c)
+{
+ for (; *s; ) {
+ if (*s == c)
+ return (char *) s;
+ if ((*is_multibyte_char_1)(*s)) {
+ s += 2;
+ } else {
+ s++;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************
+ Search char C end of S.
+ S contains generic multibyte chars.
+********************************************************************/
+
+static char *generic_multibyte_strrchr(char *s, int c)
+{
+ char *q;
+
+ for (q = 0; *s; ) {
+ if (*s == c) {
+ q = (char *) s;
+ }
+ if ((*is_multibyte_char_1)(*s)) {
+ s += 2;
+ } else {
+ s++;
+ }
+ }
+ return q;
+}
+
+/*******************************************************************
+ Generic multibyte char skip function.
+*******************************************************************/
+
+static int skip_generic_multibyte_char(char c)
+{
+ if( (*is_multibyte_char_1)(c)) {
+ return 2;
+ }
+ return 0;
+}
+
+/*******************************************************************
Code conversion
********************************************************************/
/* convesion buffer */
@@ -153,8 +376,7 @@ static char cvtbuf[1024];
/*******************************************************************
EUC <-> SJIS
********************************************************************/
-static int
-euc2sjis (register int hi, register int lo)
+static int euc2sjis (int hi, int lo)
{
if (hi & 1)
return ((hi / 2 + (hi < 0xdf ? 0x31 : 0x71)) << 8) |
@@ -163,8 +385,7 @@ euc2sjis (register int hi, register int lo)
return ((hi / 2 + (hi < 0xdf ? 0x30 : 0x70)) << 8) | (lo - 2);
}
-static int
-sjis2euc (register int hi, register int lo)
+static int sjis2euc (int hi, int lo)
{
if (lo >= 0x9f)
return ((hi * 2 - (hi >= 0xe0 ? 0xe0 : 0x60)) << 8) | (lo + 2);
@@ -177,10 +398,9 @@ sjis2euc (register int hi, register int lo)
Convert FROM contain SHIFT JIS codes to EUC codes
return converted buffer
********************************************************************/
-static char *
-sj_to_euc (const char *from, BOOL overwrite)
+static char *sj_to_euc(char *from, BOOL overwrite)
{
- register char *out;
+ char *out;
char *save;
save = (char *) from;
@@ -191,7 +411,7 @@ sj_to_euc (const char *from, BOOL overwrite)
*out++ = code;
from += 2;
} else if (is_kana (*from)) {
- *out++ = euc_kana;
+ *out++ = (char)euc_kana;
*out++ = *from++;
} else {
*out++ = *from++;
@@ -199,7 +419,7 @@ sj_to_euc (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy((char *) save, (char *) cvtbuf);
+ pstrcpy((char *) save, (char *) cvtbuf);
return (char *) save;
} else {
return cvtbuf;
@@ -210,10 +430,9 @@ sj_to_euc (const char *from, BOOL overwrite)
Convert FROM contain EUC codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-euc_to_sj (const char *from, BOOL overwrite)
+static char *euc_to_sj(char *from, BOOL overwrite)
{
- register char *out;
+ char *out;
char *save;
save = (char *) from;
@@ -232,7 +451,7 @@ euc_to_sj (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy(save, (char *) cvtbuf);
+ pstrcpy(save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -242,8 +461,7 @@ euc_to_sj (const char *from, BOOL overwrite)
/*******************************************************************
JIS7,JIS8,JUNET <-> SJIS
********************************************************************/
-static int
-sjis2jis (register int hi, register int lo)
+static int sjis2jis(int hi, int lo)
{
if (lo >= 0x9f)
return ((hi * 2 - (hi >= 0xe0 ? 0x160 : 0xe0)) << 8) | (lo - 0x7e);
@@ -252,8 +470,7 @@ sjis2jis (register int hi, register int lo)
(lo - (lo >= 0x7f ? 0x20 : 0x1f));
}
-static int
-jis2sjis (register int hi, register int lo)
+static int jis2sjis(int hi, int lo)
{
if (hi & 1)
return ((hi / 2 + (hi < 0x5f ? 0x71 : 0xb1)) << 8) |
@@ -266,11 +483,10 @@ jis2sjis (register int hi, register int lo)
Convert FROM contain JIS codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-jis8_to_sj (const char *from, BOOL overwrite)
+static char *jis8_to_sj(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -306,7 +522,7 @@ jis8_to_sj (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy (save, (char *) cvtbuf);
+ pstrcpy (save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -317,11 +533,10 @@ jis8_to_sj (const char *from, BOOL overwrite)
Convert FROM contain SHIFT JIS codes to JIS codes
return converted buffer
********************************************************************/
-static char *
-sj_to_jis8 (const char *from, BOOL overwrite)
+static char *sj_to_jis8(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -363,7 +578,7 @@ sj_to_jis8 (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy (save, (char *) cvtbuf);
+ pstrcpy (save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -374,11 +589,10 @@ sj_to_jis8 (const char *from, BOOL overwrite)
Convert FROM contain 7 bits JIS codes to SHIFT JIS codes
return converted buffer
********************************************************************/
-static char *
-jis7_to_sj (const char *from, BOOL overwrite)
+static char *jis7_to_sj(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -423,7 +637,7 @@ jis7_to_sj (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy (save, (char *) cvtbuf);
+ pstrcpy (save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -434,11 +648,10 @@ jis7_to_sj (const char *from, BOOL overwrite)
Convert FROM contain SHIFT JIS codes to 7 bits JIS codes
return converted buffer
********************************************************************/
-static char *
-sj_to_jis7 (const char *from, BOOL overwrite)
+static char *sj_to_jis7(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -500,7 +713,7 @@ sj_to_jis7 (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy (save, (char *) cvtbuf);
+ pstrcpy (save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -511,11 +724,10 @@ sj_to_jis7 (const char *from, BOOL overwrite)
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)
+static char *junet_to_sj(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -557,7 +769,7 @@ junet_to_sj (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy (save, (char *) cvtbuf);
+ pstrcpy (save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -568,11 +780,10 @@ junet_to_sj (const char *from, BOOL overwrite)
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)
+static char *sj_to_junet(char *from, BOOL overwrite)
{
- register char *out;
- register int shifted;
+ char *out;
+ int shifted;
char *save;
shifted = _KJ_ROMAN;
@@ -627,7 +838,7 @@ sj_to_junet (const char *from, BOOL overwrite)
}
*out = 0;
if (overwrite) {
- strcpy (save, (char *) cvtbuf);
+ pstrcpy (save, (char *) cvtbuf);
return save;
} else {
return cvtbuf;
@@ -638,15 +849,14 @@ sj_to_junet (const char *from, BOOL overwrite)
HEX <-> SJIS
********************************************************************/
/* ":xx" -> a byte */
-static char *
-hex_to_sj (const char *from, BOOL overwrite)
+static char *hex_to_sj(char *from, BOOL overwrite)
{
char *sp, *dp;
sp = (char *) from;
dp = cvtbuf;
while (*sp) {
- if (*sp == hex_tag && isxdigit (sp[1]) && isxdigit (sp[2])) {
+ if (*sp == hex_tag && isxdigit((int)sp[1]) && isxdigit((int)sp[2])) {
*dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2]));
sp += 3;
} else
@@ -654,7 +864,7 @@ hex_to_sj (const char *from, BOOL overwrite)
}
*dp = '\0';
if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
+ pstrcpy ((char *) from, (char *) cvtbuf);
return (char *) from;
} else {
return cvtbuf;
@@ -664,8 +874,7 @@ hex_to_sj (const char *from, BOOL overwrite)
/*******************************************************************
kanji/kana -> ":xx"
********************************************************************/
-static char *
-sj_to_hex (const char *from, BOOL overwrite)
+static char *sj_to_hex(char *from, BOOL overwrite)
{
unsigned char *sp, *dp;
@@ -691,7 +900,7 @@ sj_to_hex (const char *from, BOOL overwrite)
}
*dp = '\0';
if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
+ pstrcpy ((char *) from, (char *) cvtbuf);
return (char *) from;
} else {
return cvtbuf;
@@ -699,10 +908,41 @@ sj_to_hex (const char *from, BOOL overwrite)
}
/*******************************************************************
- kanji/kana -> ":xx"
+ CAP <-> SJIS
********************************************************************/
-static char *
-sj_to_cap (const char *from, BOOL overwrite)
+/* ":xx" CAP -> a byte */
+static char *cap_to_sj(char *from, BOOL overwrite)
+{
+ char *sp, *dp;
+
+ sp = (char *) from;
+ dp = cvtbuf;
+ while (*sp) {
+ /*
+ * The only change between this and hex_to_sj is here. sj_to_cap only
+ * translates characters greater or equal to 0x80 - make sure that here
+ * we only do the reverse (that's why the strchr is used rather than
+ * isxdigit. Based on fix from ado@elsie.nci.nih.gov (Arthur David Olson).
+ */
+ if (*sp == hex_tag && (strchr ("89abcdefABCDEF", sp[1]) != NULL) && isxdigit((int)sp[2])) {
+ *dp++ = (hex2bin (sp[1])<<4) | (hex2bin (sp[2]));
+ sp += 3;
+ } else
+ *dp++ = *sp++;
+ }
+ *dp = '\0';
+ if (overwrite) {
+ pstrcpy ((char *) from, (char *) cvtbuf);
+ return (char *) from;
+ } else {
+ return cvtbuf;
+ }
+}
+
+/*******************************************************************
+ kanji/kana -> ":xx" - CAP format.
+********************************************************************/
+static char *sj_to_cap(char *from, BOOL overwrite)
{
unsigned char *sp, *dp;
@@ -720,7 +960,7 @@ sj_to_cap (const char *from, BOOL overwrite)
}
*dp = '\0';
if (overwrite) {
- strcpy ((char *) from, (char *) cvtbuf);
+ pstrcpy ((char *) from, (char *) cvtbuf);
return (char *) from;
} else {
return cvtbuf;
@@ -730,11 +970,10 @@ sj_to_cap (const char *from, BOOL overwrite)
/*******************************************************************
sj to sj
********************************************************************/
-static char *
-sj_to_sj (const char *from, BOOL overwrite)
+static char *sj_to_sj(char *from, BOOL overwrite)
{
if (!overwrite) {
- strcpy (cvtbuf, (char *) from);
+ pstrcpy (cvtbuf, (char *) from);
return cvtbuf;
} else {
return (char *) from;
@@ -746,18 +985,17 @@ sj_to_sj (const char *from, BOOL overwrite)
_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)
+static void setup_string_function(int codes)
{
switch (codes) {
default:
+ _dos_to_unix = dos2unix_format;
+ _unix_to_dos = unix2dos_format;
+ break;
+
case SJIS_CODE:
_dos_to_unix = sj_to_sj;
_unix_to_dos = sj_to_sj;
-
break;
case EUC_CODE:
@@ -787,19 +1025,18 @@ setup_string_function (int codes)
case CAP_CODE:
_dos_to_unix = sj_to_cap;
- _unix_to_dos = hex_to_sj;
+ _unix_to_dos = cap_to_sj;
break;
}
- return codes;
}
-/*
- * Interpret coding system.
- */
-int
-interpret_coding_system (char *str, int def)
+/************************************************************************
+ Interpret coding system.
+************************************************************************/
+
+void interpret_coding_system(char *str)
{
- int codes = def;
+ int codes = UNKNOWN_CODE;
if (strequal (str, "sjis")) {
codes = SJIS_CODE;
@@ -811,7 +1048,7 @@ interpret_coding_system (char *str, int def)
} else if (strequal (str, "hex")) {
codes = HEX_CODE;
hex_tag = HEXTAG;
- } else if (strncasecmp (str, "hex", 3)) {
+ } else if (!strncasecmp (str, "hex", 3)) {
codes = HEX_CODE;
hex_tag = (str[3] ? str[3] : HEXTAG);
} else if (strequal (str, "j8bb")) {
@@ -887,9 +1124,82 @@ interpret_coding_system (char *str, int def)
jis_kso = '@';
jis_ksi = 'H';
}
- return setup_string_function (codes);
+ setup_string_function (codes);
+}
+
+/*******************************************************************
+ Non multibyte char function.
+*******************************************************************/
+
+static int skip_non_multibyte_char(char c)
+{
+ return 0;
+}
+
+/*******************************************************************
+ Function that always says a character isn't multibyte.
+*******************************************************************/
+
+static BOOL not_multibyte_char_1(char c)
+{
+ return False;
+}
+
+/*******************************************************************
+ Setup the function pointers for the functions that are replaced
+ when multi-byte codepages are used.
+
+ The dos_to_unix and unix_to_dos function pointers are only
+ replaced by setup_string_function called by interpret_coding_system
+ above.
+*******************************************************************/
+
+void initialize_multibyte_vectors( int client_codepage)
+{
+ switch( client_codepage )
+ {
+ case KANJI_CODEPAGE:
+ multibyte_strchr = (char *(*)(char *, int )) sj_strchr;
+ multibyte_strrchr = (char *(*)(char *, int )) sj_strrchr;
+ multibyte_strstr = (char *(*)(char *, char *)) sj_strstr;
+ multibyte_strtok = (char *(*)(char *, char *)) sj_strtok;
+ _skip_multibyte_char = skip_kanji_multibyte_char;
+ is_multibyte_char_1 = is_kanji_multibyte_char_1;
+ break;
+ case HANGUL_CODEPAGE:
+ multibyte_strchr = (char *(*)(char *, int )) generic_multibyte_strchr;
+ multibyte_strrchr = (char *(*)(char *, int )) generic_multibyte_strrchr;
+ multibyte_strstr = (char *(*)(char *, char *)) generic_multibyte_strstr;
+ multibyte_strtok = (char *(*)(char *, char *)) generic_multibyte_strtok;
+ _skip_multibyte_char = skip_generic_multibyte_char;
+ is_multibyte_char_1 = hangul_is_multibyte_char_1;
+ break;
+ case BIG5_CODEPAGE:
+ multibyte_strchr = (char *(*)(char *, int )) generic_multibyte_strchr;
+ multibyte_strrchr = (char *(*)(char *, int )) generic_multibyte_strrchr;
+ multibyte_strstr = (char *(*)(char *, char *)) generic_multibyte_strstr;
+ multibyte_strtok = (char *(*)(char *, char *)) generic_multibyte_strtok;
+ _skip_multibyte_char = skip_generic_multibyte_char;
+ is_multibyte_char_1 = big5_is_multibyte_char_1;
+ break;
+ case SIMPLIFIED_CHINESE_CODEPAGE:
+ multibyte_strchr = (char *(*)(char *, int )) generic_multibyte_strchr;
+ multibyte_strrchr = (char *(*)(char *, int )) generic_multibyte_strrchr;
+ multibyte_strstr = (char *(*)(char *, char *)) generic_multibyte_strstr;
+ multibyte_strtok = (char *(*)(char *, char *)) generic_multibyte_strtok;
+ _skip_multibyte_char = skip_generic_multibyte_char;
+ is_multibyte_char_1 = simpch_is_multibyte_char_1;
+ break;
+ /*
+ * Single char size code page.
+ */
+ default:
+ multibyte_strchr = (char *(*)(char *, int )) strchr;
+ multibyte_strrchr = (char *(*)(char *, int )) strrchr;
+ multibyte_strstr = (char *(*)(char *, char *)) strstr;
+ multibyte_strtok = (char *(*)(char *, char *)) strtok;
+ _skip_multibyte_char = skip_non_multibyte_char;
+ is_multibyte_char_1 = not_multibyte_char_1;
+ break;
+ }
}
-#else
-int kanji_dummy_procedure(void)
-{return 0;}
-#endif /* KANJI */
diff --git a/source/lib/md4.c b/source/lib/md4.c
index 485e231a784..30f2b6b8c6b 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, 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, 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/membuffer.c b/source/lib/membuffer.c
new file mode 100644
index 00000000000..85f63e8c065
--- /dev/null
+++ b/source/lib/membuffer.c
@@ -0,0 +1,358 @@
+/*
+ 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
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*******************************************************************
+ *
+ * Description: memory buffer / stream management.
+ * Author : Luke K C Leighton
+ * Created : Dec 1997
+ *
+
+ * this module is intended for use in streaming data in and out of
+ * buffers. it is intended that a single data stream be subdivided
+ * into manageable sections.
+
+ * for example, an rpc header contains a length field, but until the
+ * data has been created, the length is unknown. using this module,
+ * the header section can be tacked onto the front of the data memory
+ * list once the size of the data section preceding it is known.
+
+ * the "margin" can be used to over-run and retrospectively lengthen
+ * the buffer. this is to save time in some of the loops, where it is
+ * not particularly desirable to realloc data by 1, 2 or 4 bytes
+ * repetitively...
+
+ * each memory buffer contains a start and end offset. the end of
+ * one buffer should equal to the start of the next in the chain.
+ * (end - start = len, instead of end - start + 1 = len)
+
+ * the debug log levels are very high in some of the routines: you
+ * have no idea how boring it gets staring at debug output from these
+
+ ********************************************************************/
+
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/*******************************************************************
+ initialise a memory buffer.
+ ********************************************************************/
+void mem_init(struct mem_buf *buf, int margin)
+{
+ buf->dynamic = True;
+ buf->data = NULL;
+ buf->data_size = 0;
+ buf->data_used = 0;
+
+ buf->margin = margin;
+
+ buf->next = NULL;
+
+ buf->offset.start = 0;
+ buf->offset.end = 0;
+}
+
+/*******************************************************************
+ initialise a memory buffer.
+
+ dynamic indicates memory has been dynamically allocated.
+ if mem_free is called, the memory will be freed.
+ ********************************************************************/
+void mem_create(struct mem_buf *buf, char *data, int size, int margin, BOOL dynamic)
+{
+ buf->dynamic = dynamic;
+ buf->data = data;
+ buf->data_size = size;
+ buf->data_used = size;
+
+ buf->margin = margin;
+
+ buf->next = NULL;
+
+ buf->offset.start = 0;
+ buf->offset.end = size;
+}
+
+/*******************************************************************
+ allocate a memory buffer. assume it's empty
+ ********************************************************************/
+BOOL mem_alloc_data(struct mem_buf *buf, int size)
+{
+ if (!buf->dynamic)
+ {
+ DEBUG(3,("mem_alloc_data: warning - memory buffer type is set to static\n"));
+ }
+
+ buf->data_size = size + buf->margin;
+ buf->data_used = size;
+
+ buf->data = malloc(buf->data_size);
+
+ if (buf->data == NULL)
+ {
+ DEBUG(3,("mem_alloc: could not malloc size %d\n",
+ buf->data_size));
+ mem_init(buf, buf->margin);
+
+ return False;
+ }
+
+ bzero(buf->data, buf->data_size);
+
+ return True;
+}
+
+/*******************************************************************
+ allocates a memory buffer structure
+ ********************************************************************/
+BOOL mem_buf_copy(char *copy_into, struct mem_buf *buf,
+ uint32 offset, uint32 len)
+{
+ uint32 end = offset + len;
+ char *q = NULL;
+ uint32 data_len = mem_buf_len(buf);
+ uint32 start_offset = offset;
+ struct mem_buf **bcp = &buf;
+
+ if (buf == NULL || copy_into == NULL) return False;
+
+ DEBUG(200,("mem_buf_copy: data[%d..%d] offset %d len %d\n",
+ buf->offset.start, data_len, offset, len));
+
+ /* there's probably an off-by-one bug, here, and i haven't even tested the code :-) */
+ while (offset < end && ((q = mem_data(bcp, offset)) != NULL))
+ {
+ uint32 copy_len = (*bcp)->offset.end - offset;
+
+ DEBUG(200,("\tdata[%d..%d] - offset %d len %d\n",
+ (*bcp)->offset.start, (*bcp)->offset.end,
+ offset, copy_len));
+
+ memcpy(copy_into, q, copy_len);
+
+ offset += copy_len;
+ copy_into += copy_len;
+ }
+
+ if ((*bcp) != NULL)
+ {
+ DEBUG(200,("mem_buf_copy: copied %d bytes\n", offset - start_offset));
+ }
+ else
+ {
+ DEBUG(200,("mem_buf_copy: failed\n"));
+ }
+
+ return buf != NULL;
+}
+
+/*******************************************************************
+ allocates a memory buffer structure
+ ********************************************************************/
+BOOL mem_buf_init(struct mem_buf **buf, uint32 margin)
+{
+ if (buf == NULL) return False;
+
+ if ((*buf) == NULL)
+ {
+ (*buf) = malloc(sizeof(**buf));
+ if ((*buf) != NULL)
+ {
+ mem_init((*buf), margin);
+ return True;
+ }
+ }
+ else
+ {
+ (*buf)->margin = margin;
+ return True;
+ }
+ return False;
+}
+
+/*******************************************************************
+ frees up a memory buffer.
+ ********************************************************************/
+void mem_buf_free(struct mem_buf **buf)
+{
+ if (buf == NULL) return;
+ if ((*buf) == NULL) return;
+
+ mem_free_data(*buf); /* delete memory data */
+ free(*buf); /* delete item */
+ (*buf) = NULL;
+}
+
+/*******************************************************************
+ frees a memory buffer chain. assumes that all items are malloced.
+ ********************************************************************/
+static void mem_free_chain(struct mem_buf **buf)
+{
+ if (buf == NULL) return;
+ if ((*buf) == NULL) return;
+
+ if ((*buf)->next != NULL)
+ {
+ mem_free_chain(&((*buf)->next)); /* delete all other items in chain */
+ }
+ mem_buf_free(buf);
+}
+
+/*******************************************************************
+ frees a memory buffer.
+ ********************************************************************/
+void mem_free_data(struct mem_buf *buf)
+{
+ if (buf == NULL) return;
+
+ if (buf->data != NULL && buf->dynamic)
+ {
+ free(buf->data); /* delete data in this structure */
+ }
+ mem_init(buf, buf->margin);
+}
+
+/*******************************************************************
+ reallocate a memory buffer, including a safety margin
+ ********************************************************************/
+BOOL mem_realloc_data(struct mem_buf *buf, int new_size)
+{
+ char *new_data;
+
+ if (!buf->dynamic)
+ {
+ DEBUG(3,("mem_realloc_data: memory buffer has not been dynamically allocated!\n"));
+ return False;
+ }
+
+ if (new_size == 0)
+ {
+ mem_free_data(buf);
+ return True;
+ }
+
+ new_data = Realloc(buf->data, new_size + buf->margin);
+
+ if (new_data != NULL)
+ {
+ buf->data = new_data;
+ buf->data_size = new_size + buf->margin;
+ buf->data_used = new_size;
+ }
+ else if (buf->data_size <= new_size)
+ {
+ DEBUG(3,("mem_realloc: warning - could not realloc to %d(+%d)\n",
+ new_size, buf->margin));
+
+ buf->data_used = new_size;
+ }
+ else
+ {
+ DEBUG(3,("mem_realloc: error - could not realloc to %d\n",
+ new_size));
+
+ mem_free_data(buf);
+ return False;
+ }
+
+ return True;
+}
+
+/*******************************************************************
+ reallocate a memory buffer, retrospectively :-)
+ ********************************************************************/
+BOOL mem_grow_data(struct mem_buf **buf, BOOL io, int new_size, BOOL force_grow)
+{
+ if (new_size + (*buf)->margin >= (*buf)->data_size)
+ {
+ if (io && !force_grow)
+ {
+ DEBUG(3,("mem_grow_data: cannot resize when reading from a data stream\n"));
+ }
+ else
+ {
+ return mem_realloc_data((*buf), new_size);
+ }
+ }
+ return True;
+}
+
+/*******************************************************************
+ search for a memory buffer that falls within the specified offset
+ ********************************************************************/
+static BOOL mem_find(struct mem_buf **buf, uint32 offset)
+{
+ struct mem_buf *f;
+ if (buf == NULL) return False;
+
+ f = *buf;
+
+ DEBUG(200,("mem_find: data[%d..%d] offset: %d\n",
+ f->offset.start, f->offset.end, offset));
+
+ while (f != NULL && offset >= f->offset.end)
+ {
+ f = f->next;
+
+ DEBUG(200,("mem_find: next[%d..%d]\n",
+ f->offset.start, f->offset.end));
+ }
+
+ (*buf) = f;
+
+ DEBUG(200,("mem_find: found data[%d..%d]\n",
+ (*buf)->offset.start,(*buf)->offset.end));
+
+ return f != NULL;
+}
+
+
+/*******************************************************************
+ add up the lengths of all sections.
+ ********************************************************************/
+uint32 mem_buf_len(struct mem_buf *buf)
+{
+ int len = 0;
+ while (buf != NULL)
+ {
+ len += buf->offset.end - buf->offset.start;
+ buf = buf->next;
+ }
+ return len;
+}
+
+
+/*******************************************************************
+ return the memory location specified by offset. may return NULL.
+ ********************************************************************/
+char *mem_data(struct mem_buf **buf, uint32 offset)
+{
+ if (mem_find(buf, offset))
+ {
+ return &((*buf)->data[offset - (*buf)->offset.start]);
+ }
+ return NULL;
+}
+
+
diff --git a/source/lib/netatalk.c b/source/lib/netatalk.c
new file mode 100644
index 00000000000..ae0a57154e1
--- /dev/null
+++ b/source/lib/netatalk.c
@@ -0,0 +1,159 @@
+/*
+ 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
+
+extern int DEBUGLEVEL;
+
+/*****************
+ 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/netmask.c b/source/lib/netmask.c
new file mode 100644
index 00000000000..d9bc06c47a9
--- /dev/null
+++ b/source/lib/netmask.c
@@ -0,0 +1,353 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ code to query kernel netmask
+ 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 netmask for an interface 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.
+
+*/
+
+#ifndef AUTOCONF
+#include "config.h"
+#endif
+
+#ifdef HAVE_NETMASK_IFCONF
+
+#include <stdio.h>
+#include <unistd.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 <net/if.h>
+
+#ifndef SIOCGIFCONF
+#include <sys/sockio.h>
+#endif
+
+
+/****************************************************************************
+ get the netmask address for a local interface
+****************************************************************************/
+int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask)
+{
+ struct ifconf ifc;
+ char buff[2048];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+#ifdef DEBUG
+ fprintf(stderr,"socket failed\n");
+#endif
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+#ifdef DEBUG
+ fprintf(stderr,"SIOCGIFCONF failed\n");
+#endif
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+
+ n = ifc.ifc_len / sizeof(struct ifreq);
+
+#ifdef DEBUG
+ fprintf(stderr,"%d interfaces - looking for %s\n",
+ n, inet_ntoa(*ipaddr));
+#endif
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i=n-1;i>=0;i--) {
+ if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
+#ifdef DEBUG
+ fprintf(stderr,"SIOCGIFADDR failed\n");
+#endif
+ continue;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"interface %s\n",
+ inet_ntoa((*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr));
+#endif
+ if (ipaddr->s_addr !=
+ (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr.s_addr) {
+ continue;
+ }
+
+ if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
+#ifdef DEBUG
+ fprintf(stderr,"SIOCGIFNETMASK failed\n");
+#endif
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ (*nmask) = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
+#ifdef DEBUG
+ fprintf(stderr,"netmask %s\n", inet_ntoa(*nmask));
+#endif
+ return 0;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"interface not found\n");
+#endif
+
+ close(fd);
+ return -1;
+}
+
+#elif defined(HAVE_NETMASK_IFREQ)
+
+#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 <net/if.h>
+
+#ifndef SIOCGIFCONF
+#include <sys/sockio.h>
+#endif
+
+#ifndef I_STR
+#include <sys/stropts.h>
+#endif
+
+
+/****************************************************************************
+this should cover most of the rest of systems
+****************************************************************************/
+ int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask)
+{
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ struct ifconf *ifc;
+ char buff[2048];
+ int fd, i, n;
+ struct ifreq *ifr=NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+#ifdef DEBUG
+ fprintf(stderr,"socket failed\n");
+#endif
+ return -1;
+ }
+
+ 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(fd, I_STR, &strioctl) < 0) {
+#ifdef DEBUG
+ fprintf(stderr,"SIOCGIFCONF failed\n");
+#endif
+ close(fd);
+ return -1;
+ }
+
+ ifr = (struct ifreq *)ifc->ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ n = ifc->ifc_len / sizeof(struct ifreq);
+
+ for (i = 0; i<n; i++, ifr++) {
+#ifdef DEBUG
+ fprintf(stderr,"interface %s\n",
+ inet_ntoa((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr.s_addr));
+#endif
+ if (ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (i == n) {
+ fprintf(stderr,"interface not found\n");
+ close(fd);
+ return -1;
+ }
+#endif
+
+ ifreq = *ifr;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(fd, I_STR, &strioctl) != 0) {
+#ifdef DEBUG
+ fprintf(stderr,"Failed SIOCGIFNETMASK\n");
+#endif
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ *nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+#ifdef DEBUG
+ fprintf(stderr,"netmask %s\n", inet_ntoa(*nmask));
+#endif
+ return 0;
+}
+
+#elif defined(HAVE_NETMASK_AIX)
+
+#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 <net/if.h>
+
+#ifndef SIOCGIFCONF
+#include <sys/sockio.h>
+#endif
+
+/****************************************************************************
+this one is for AIX
+****************************************************************************/
+ int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask)
+{
+ char buff[2048];
+ int fd, i, n;
+ struct ifconf ifc;
+ struct ifreq *ifr=NULL;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+#ifdef DEBUG
+ fprintf(stderr,"socket failed\n");
+#endif
+ return -1;
+ }
+
+
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+#ifdef DEBUG
+ fprintf(stderr,"SIOCGIFCONF failed\n");
+#endif
+ close(fd);
+ return -1;
+ }
+
+ ifr = ifc.ifc_req;
+ /* Loop through interfaces, looking for given IP address */
+ i = ifc.ifc_len;
+ while (i > 0) {
+#ifdef DEBUG
+ fprintf(stderr,"interface %s\n",
+ inet_ntoa((*(struct sockaddr_in *)&ifr->ifr_addr).sin_addr));
+#endif
+ if (ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ break;
+ }
+ i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
+ ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len +
+ IFNAMSIZ);
+ }
+
+
+#ifdef DEBUG
+ if (i <= 0) {
+ fprintf(stderr,"interface not found\n");
+ close(fd);
+ return -1;
+ }
+#endif
+
+ if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
+#ifdef DEBUG
+ fprintf(stderr,"SIOCGIFNETMASK failed\n");
+#endif
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ (*nmask) = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+#ifdef DEBUG
+ fprintf(stderr,"netmask %s\n", inet_ntoa(*nmask));
+#endif
+ return 0;
+}
+
+#else /* a dummy version */
+struct in_addr; /* it may not have been declared before */
+ int get_netmask(struct in_addr *ipaddr, struct in_addr *nmask)
+{
+ return -1;
+}
+#endif
+
+
+#ifdef AUTOCONF
+/* this is the autoconf driver to test get_netmask() */
+
+ main()
+{
+ char buf[1024];
+ struct hostent *hp;
+ struct in_addr ip, nmask;
+
+ if (gethostname(buf, sizeof(buf)-1) != 0) {
+ fprintf(stderr,"gethostname failed\n");
+ exit(1);
+ }
+
+ hp = gethostbyname(buf);
+
+ if (!hp) {
+ fprintf(stderr,"gethostbyname failed\n");
+ exit(1);
+ }
+
+ memcpy((char *)&ip, (char *)hp->h_addr, hp->h_length);
+
+ if (get_netmask(&ip, &nmask) == 0) exit(0);
+
+ fprintf(stderr,"get_netmask failed\n");
+ exit(1);
+}
+#endif
diff --git a/source/lib/pidfile.c b/source/lib/pidfile.c
new file mode 100644
index 00000000000..7e98438dba7
--- /dev/null
+++ b/source/lib/pidfile.c
@@ -0,0 +1,95 @@
+/*
+ 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"
+
+
+extern int DEBUGLEVEL;
+
+#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)
+{
+ FILE *f;
+ unsigned ret;
+ pstring pidFile;
+
+ slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name);
+
+ f = fopen(pidFile, "r");
+ if (!f) {
+ return 0;
+ }
+
+ if (fscanf(f,"%u", &ret) != 1) {
+ fclose(f);
+ return 0;
+ }
+ fclose(f);
+
+ if (!process_exists(ret)) return 0;
+
+ return (pid_t)ret;
+}
+
+/* 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;
+ int pid;
+
+ slprintf(pidFile, sizeof(pidFile)-1, "%s/%s.pid", lp_lockdir(), name);
+
+ pid = pidfile_pid(name);
+ if (pid > 0 && process_exists(pid)) {
+ DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
+ name, pidFile, pid));
+ exit(1);
+ }
+
+ fd = open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY, 0644);
+ if (fd < 0) {
+ 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) 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/replace.c b/source/lib/replace.c
new file mode 100644
index 00000000000..6441efe44c7
--- /dev/null
+++ b/source/lib/replace.c
@@ -0,0 +1,295 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+
+ 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
+
+
+#ifndef HAVE_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)
+{
+ 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++;
+ }
+ }
+
+ 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
+
+
+#ifndef HAVE_INNETGR
+/*
+ * Search for a match in a netgroup. This replaces it on broken systems.
+ */
+ int innetgr(char *group,char *host,char *user,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
+
+
+
+#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
+ 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
+
+
+#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
+
+#ifndef HAVE_STRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+ char *strdup(const char *s)
+{
+ int 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
+
+#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
+ slprintf(buf, 17, "%d.%d.%d.%d",
+ (int)p[3], (int)p[2], (int)p[1], (int)p[0]);
+#endif
+ return buf;
+}
+#endif
diff --git a/source/lib/signal.c b/source/lib/signal.c
new file mode 100644
index 00000000000..bb1c6fe189b
--- /dev/null
+++ b/source/lib/signal.c
@@ -0,0 +1,102 @@
+/*
+ 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
+****************************************************************************/
+static void sig_cld(int signum)
+{
+ while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0) ;
+
+ CatchSignal(SIGCLD, sig_cld);
+}
+
+
+
+/*******************************************************************
+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)
+ int block_mask = sigmask(signum);
+ static int oldmask = 0;
+ if (block) {
+ oldmask = sigblock(block_mask);
+ } else {
+ sigsetmask(oldmask);
+ }
+#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
+ act.sa_flags = SA_RESTART;
+#endif
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,signum);
+ sigaction(signum,&act,NULL);
+#else
+ /* 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);
+}
diff --git a/source/lib/slprintf.c b/source/lib/slprintf.c
new file mode 100644
index 00000000000..acdcfee38fd
--- /dev/null
+++ b/source/lib/slprintf.c
@@ -0,0 +1,111 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ snprintf replacement
+ 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 DEBUGLEVEL;
+
+
+/* this is like vsnprintf but the 'n' limit does not include
+ the terminating null. So if you have a 1024 byte buffer then
+ pass 1023 for n */
+int vslprintf(char *str, int n, char *format, va_list ap)
+{
+#ifdef HAVE_VSNPRINTF
+ int ret = vsnprintf(str, n, format, ap);
+ if (ret > n || ret < 0) {
+ str[n] = 0;
+ return -1;
+ }
+ str[ret] = 0;
+ return ret;
+#else
+ static char *buf;
+ static int len=8000;
+ int ret;
+
+ /* this code is NOT a proper vsnprintf() implementation. It
+ relies on the fact that all calls to slprintf() in Samba
+ pass strings which have already been through pstrcpy() or
+ fstrcpy() and never more than 2 strings are
+ concatenated. This means the above buffer is absolutely
+ ample and can never be overflowed.
+
+ In the future we would like to replace this with a proper
+ vsnprintf() implementation but right now we need a solution
+ that is secure and portable. This is it. */
+
+ if (!buf) {
+ buf = malloc(len);
+ if (!buf) {
+ /* can't call debug or we would recurse */
+ exit(1);
+ }
+ }
+
+ vsprintf(buf, format, ap);
+ ret = strlen(buf);
+
+ if (ret < 0) {
+ str[0] = 0;
+ return -1;
+ }
+
+ if (ret < n) {
+ n = ret;
+ } else if (ret > n) {
+ ret = -1;
+ }
+
+ buf[n] = 0;
+
+ memcpy(str, buf, n+1);
+
+ return ret;
+#endif
+}
+
+#ifdef HAVE_STDARG_H
+ int slprintf(char *str, int n, char *format, ...)
+{
+#else
+ int slprintf(va_alist)
+va_dcl
+{
+ char *str, *format;
+ int n;
+#endif
+ va_list ap;
+ int ret;
+
+#ifdef HAVE_STDARG_H
+ va_start(ap, format);
+#else
+ va_start(ap);
+ str = va_arg(ap,char *);
+ n = va_arg(ap,int);
+ format = va_arg(ap,char *);
+#endif
+
+ ret = vslprintf(str,n,format,ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/source/lib/smbrun.c b/source/lib/smbrun.c
new file mode 100644
index 00000000000..86d7cf9e03f
--- /dev/null
+++ b/source/lib/smbrun.c
@@ -0,0 +1,178 @@
+/*
+ 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;
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+This is a utility function of smbrun(). It must be called only from
+the child as it may leave the caller in a privilaged state.
+****************************************************************************/
+static BOOL setup_stdout_file(char *outfile,BOOL shared)
+{
+ int fd;
+ SMB_STRUCT_STAT st;
+ mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH;
+ int flags = O_RDWR|O_CREAT|O_TRUNC|O_EXCL;
+
+ close(1);
+
+ if (shared) {
+ /* become root - unprivilaged users can't delete these files */
+#ifdef HAVE_SETRESUID
+ setresgid(0,0,0);
+ setresuid(0,0,0);
+#else
+ setuid(0);
+ seteuid(0);
+#endif
+ }
+
+ if(sys_stat(outfile, &st) == 0) {
+ /* Check we're not deleting a device file. */
+ if(st.st_mode & S_IFREG)
+ unlink(outfile);
+ else
+ flags = O_RDWR;
+ }
+ /* now create the file */
+ fd = open(outfile,flags,mode);
+
+ if (fd == -1) return False;
+
+ if (fd != 1) {
+ if (dup2(fd,1) != 0) {
+ DEBUG(2,("Failed to create stdout file descriptor\n"));
+ close(fd);
+ return False;
+ }
+ close(fd);
+ }
+ return True;
+}
+
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfile (or discard it if outfile is NULL).
+
+if shared is True then ensure the file will be writeable by all users
+but created such that its owned by root. This overcomes a security hole.
+
+if shared is not set then open the file with O_EXCL set
+****************************************************************************/
+int smbrun(char *cmd,char *outfile,BOOL shared)
+{
+ int fd,pid;
+ int uid = current_user.uid;
+ int gid = current_user.gid;
+
+ /*
+ * Lose any kernel oplock capabilities we may have.
+ */
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
+
+#ifndef HAVE_EXECL
+ int ret;
+ pstring syscmd;
+ char *path = lp_smbrun();
+
+ /* in the old method we use system() to execute smbrun which then
+ executes the command (using system() again!). This involves lots
+ of shell launches and is very slow. It also suffers from a
+ potential security hole */
+ if (!file_exist(path,NULL)) {
+ DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path));
+ return(1);
+ }
+
+ slprintf(syscmd,sizeof(syscmd)-1,"%s %d %d \"(%s 2>&1) > %s\"",
+ path,uid,gid,cmd,
+ outfile?outfile:"/dev/null");
+
+ DEBUG(5,("smbrun - running %s ",syscmd));
+ ret = system(syscmd);
+ DEBUG(5,("gave %d\n",ret));
+ return(ret);
+#else
+ /* in this newer method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ if ((pid=fork())) {
+ int status=0;
+ /* the parent just waits for the child to exit */
+ if (sys_waitpid(pid,&status,0) != pid) {
+ DEBUG(2,("waitpid(%d) : %s\n",pid,strerror(errno)));
+ return -1;
+ }
+ return status;
+ }
+
+
+ /* 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 (outfile && !setup_stdout_file(outfile,shared)) {
+ exit(80);
+ }
+
+ /* now completely lose our privilages. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+#ifdef HAVE_SETRESUID
+ 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 || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privilages - do not execute
+ the command */
+ exit(81); /* we can't print stuff at this stage,
+ instead use exit codes for debugging */
+ }
+
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ for (fd=3;fd<256;fd++) close(fd);
+
+ execl("/bin/sh","sh","-c",cmd,NULL);
+
+ /* not reached */
+ exit(82);
+#endif
+ return 1;
+}
diff --git a/source/lib/system.c b/source/lib/system.c
index 938746e9c9d..f474633dd11 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
@@ -25,13 +25,17 @@ 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.
*/
@@ -40,7 +44,7 @@ this replaces the normal select() system call
return if some data has arrived on one of the file descriptors
return -1 means error
********************************************************************/
-#ifdef NO_SELECT
+#ifndef HAVE_SELECT
static int pollfd(int fd)
{
int r=0;
@@ -56,7 +60,7 @@ static int pollfd(int fd)
return(r);
}
-int sys_select(fd_set *fds,struct timeval *tval)
+int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
{
fd_set fds2;
int counter=0;
@@ -65,147 +69,411 @@ int sys_select(fd_set *fds,struct timeval *tval)
FD_ZERO(&fds2);
while (1)
- {
- int i;
- for (i=0;i<255;i++) {
- if (FD_ISSET(i,fds) && pollfd(i)>0) {
- found++;
- FD_SET(i,&fds2);
- }
+ {
+ int i;
+ for (i=0;i<maxfd;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 (found) {
+ memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
+ return(found);
+ }
- if (tval && tval.tv_sec < counter) return(0);
+ if (tval && tval->tv_sec < counter) return(0);
sleep(1);
counter++;
- }
+ }
}
-#else
-int sys_select(fd_set *fds,struct timeval *tval)
+#else /* !NO_SELECT */
+int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
{
+#ifdef USE_POLL
+ struct pollfd pfd[256];
+ int i;
+ int maxpoll;
+ int timeout;
+ int pollrtn;
+
+ maxpoll = 0;
+ for( i = 0; i < maxfd; i++) {
+ if(FD_ISSET(i,fds)) {
+ struct pollfd *pfdp = &pfd[maxpoll++];
+ pfdp->fd = i;
+ pfdp->events = POLLIN;
+ pfdp->revents = 0;
+ }
+ }
+
+ timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
+ -1;
+ errno = 0;
+ do {
+ pollrtn = poll( &pfd[0], maxpoll, timeout);
+ } while (pollrtn<0 && errno == EINTR);
+
+ FD_ZERO(fds);
+
+ for( i = 0; i < maxpoll; i++)
+ if( pfd[i].revents & POLLIN )
+ FD_SET(pfd[i].fd,fds);
+
+ return pollrtn;
+#else /* USE_POLL */
+
struct timeval t2;
int selrtn;
do {
if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
errno = 0;
- selrtn = select(16,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
+ selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
} while (selrtn<0 && errno == EINTR);
return(selrtn);
}
+#endif /* USE_POLL */
+#endif /* NO_SELECT */
+
+/*******************************************************************
+A stat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_stat(char *fname,SMB_STRUCT_STAT *sbuf)
+{
+#if defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
+ return stat64(fname, sbuf);
+#else
+ return stat(fname, sbuf);
#endif
+}
+/*******************************************************************
+ An fstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
+{
+#if defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
+ return fstat64(fd, sbuf);
+#else
+ return fstat(fd, sbuf);
+#endif
+}
+
+/*******************************************************************
+ An lstat() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_lstat(char *fname,SMB_STRUCT_STAT *sbuf)
+{
+#if defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
+ return lstat64(fname, sbuf);
+#else
+ return lstat(fname, sbuf);
+#endif
+}
+
+/*******************************************************************
+ An ftruncate() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_ftruncate(int fd, SMB_OFF_T offset)
+{
+#if defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
+ return ftruncate64(fd, offset);
+#else
+ return ftruncate(fd, offset);
+#endif
+}
+
+/*******************************************************************
+ An lseek() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
+{
+#if defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
+ return lseek64(fd, offset, whence);
+#else
+ return lseek(fd, offset, whence);
+#endif
+}
+
+/*******************************************************************
+ An fseek() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
+{
+#if defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
+ return fseek64(fp, offset, whence);
+#else
+ return fseek(fp, offset, whence);
+#endif
+}
+
+/*******************************************************************
+ An ftell() wrapper that will deal with 64 bit filesizes.
+********************************************************************/
+
+SMB_OFF_T sys_ftell(FILE *fp)
+{
+#if defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
+ return (SMB_OFF_T)ftell64(fp);
+#else
+ return (SMB_OFF_T)ftell(fp);
+#endif
+}
/*******************************************************************
-just a unlink wrapper
+just a unlink wrapper that calls dos_to_unix.
********************************************************************/
-int sys_unlink(char *fname)
+int dos_unlink(char *fname)
{
return(unlink(dos_to_unix(fname,False)));
}
/*******************************************************************
-a simple open() wrapper
+a simple open() wrapper that calls dos_to_unix.
********************************************************************/
-int sys_open(char *fname,int flags,int mode)
+int dos_open(char *fname,int flags,mode_t mode)
{
return(open(dos_to_unix(fname,False),flags,mode));
}
/*******************************************************************
-a simple opendir() wrapper
+a simple opendir() wrapper that calls dos_to_unix
********************************************************************/
-DIR *sys_opendir(char *dname)
+DIR *dos_opendir(char *dname)
{
- return(opendir(dos_to_unix(dname,False)));
+ return(opendir(dos_to_unix(dname,False)));
}
-
/*******************************************************************
-and a stat() wrapper
+and a stat() wrapper that calls dos_to_unix.
********************************************************************/
-int sys_stat(char *fname,struct stat *sbuf)
+int dos_stat(char *fname,SMB_STRUCT_STAT *sbuf)
{
- return(stat(dos_to_unix(fname,False),sbuf));
+ return(sys_stat(dos_to_unix(fname,False),sbuf));
}
/*******************************************************************
-don't forget lstat()
+The wait() calls vary between systems
********************************************************************/
-int sys_lstat(char *fname,struct stat *sbuf)
+int sys_waitpid(pid_t pid,int *status,int options)
{
- return(lstat(dos_to_unix(fname,False),sbuf));
+#ifdef HAVE_WAITPID
+ return waitpid(pid,status,options);
+#else /* HAVE_WAITPID */
+ return wait4(pid, status, options, NULL);
+#endif /* HAVE_WAITPID */
}
+/*******************************************************************
+don't forget lstat() that calls dos_to_unix.
+********************************************************************/
+int dos_lstat(char *fname,SMB_STRUCT_STAT *sbuf)
+{
+ return(sys_lstat(dos_to_unix(fname,False),sbuf));
+}
/*******************************************************************
-mkdir() gets a wrapper
+mkdir() gets a wrapper that calls dos_to_unix.
********************************************************************/
-int sys_mkdir(char *dname,int mode)
+int dos_mkdir(char *dname,mode_t mode)
{
return(mkdir(dos_to_unix(dname,False),mode));
}
-
/*******************************************************************
-do does rmdir()
+do does rmdir() - call dos_to_unix
********************************************************************/
-int sys_rmdir(char *dname)
+int dos_rmdir(char *dname)
{
return(rmdir(dos_to_unix(dname,False)));
}
-
/*******************************************************************
-I almost forgot chdir()
+I almost forgot chdir() - call dos_to_unix.
********************************************************************/
-int sys_chdir(char *dname)
+int dos_chdir(char *dname)
{
return(chdir(dos_to_unix(dname,False)));
}
-
/*******************************************************************
-now for utime()
+now for utime() - call dos_to_unix.
********************************************************************/
-int sys_utime(char *fname,struct utimbuf *times)
+int dos_utime(char *fname,struct utimbuf *times)
{
+ /* if the modtime is 0 or -1 then ignore the call and
+ return success */
+ if (times->modtime == (time_t)0 || times->modtime == (time_t)-1)
+ return 0;
+
+ /* if the access time is 0 or -1 then set it to the modtime */
+ if (times->actime == (time_t)0 || times->actime == (time_t)-1)
+ times->actime = times->modtime;
+
return(utime(dos_to_unix(fname,False),times));
}
+/*********************************************************
+for rename across filesystems Patch from Warren Birnbaum
+<warrenb@hpcvscdp.cv.hp.com>
+**********************************************************/
+
+static int copy_reg(char *source, const char *dest)
+{
+ SMB_STRUCT_STAT source_stats;
+ int ifd;
+ int ofd;
+ char *buf;
+ int len; /* Number of bytes read into `buf'. */
+
+ sys_lstat (source, &source_stats);
+ if (!S_ISREG (source_stats.st_mode))
+ return 1;
+
+ if (unlink (dest) && errno != ENOENT)
+ return 1;
+
+ if((ifd = open (source, O_RDONLY, 0)) < 0)
+ return 1;
+
+ if((ofd = open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 )
+ {
+ close (ifd);
+ return 1;
+ }
+
+ if((buf = malloc( COPYBUF_SIZE )) == NULL)
+ {
+ close (ifd);
+ close (ofd);
+ unlink (dest);
+ return 1;
+ }
+
+ while ((len = read(ifd, buf, COPYBUF_SIZE)) > 0)
+ {
+ if (write_data(ofd, buf, len) < 0)
+ {
+ close (ifd);
+ close (ofd);
+ unlink (dest);
+ free(buf);
+ return 1;
+ }
+ }
+ free(buf);
+ if (len < 0)
+ {
+ close (ifd);
+ close (ofd);
+ unlink (dest);
+ return 1;
+ }
+
+ if (close (ifd) < 0)
+ {
+ close (ofd);
+ return 1;
+ }
+ if (close (ofd) < 0)
+ return 1;
+
+ /* chown turns off set[ug]id bits for non-root,
+ so do the chmod last. */
+
+ /* Try to copy the old file's modtime and access time. */
+ {
+ struct utimbuf tv;
+
+ tv.actime = source_stats.st_atime;
+ tv.modtime = source_stats.st_mtime;
+ if (utime (dest, &tv))
+ return 1;
+ }
+
+ /* Try to preserve ownership. For non-root it might fail, but that's ok.
+ But root probably wants to know, e.g. if NFS disallows it. */
+ if (chown (dest, source_stats.st_uid, source_stats.st_gid)
+ && (errno != EPERM))
+ return 1;
+
+ if (chmod (dest, source_stats.st_mode & 07777))
+ return 1;
+
+ unlink (source);
+ return 0;
+}
+
/*******************************************************************
-for rename()
+for rename() - call dos_to_unix.
********************************************************************/
-int sys_rename(char *from, char *to)
+int dos_rename(char *from, char *to)
{
-#ifdef KANJI
+ int rcode;
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 */
+
+ pstrcpy (zfrom, dos_to_unix (from, False));
+ pstrcpy (zto, dos_to_unix (to, False));
+ rcode = rename (zfrom, zto);
+
+ if (errno == EXDEV)
+ {
+ /* Rename across filesystems needed. */
+ rcode = copy_reg (zfrom, zto);
+ }
+ return rcode;
}
+/*******************************************************************
+for chmod - call dos_to_unix.
+********************************************************************/
+int dos_chmod(char *fname,mode_t mode)
+{
+ return(chmod(dos_to_unix(fname,False),mode));
+}
+
+/*******************************************************************
+for getwd - takes a UNIX directory name and returns the name
+in dos format.
+********************************************************************/
+char *dos_getwd(char *s)
+{
+ char *wd;
+#ifdef HAVE_GETCWD
+ wd = (char *)getcwd(s, sizeof (pstring));
+#else
+ wd = (char *)getwd(s);
+#endif
+ if (wd)
+ unix_to_dos(wd, True);
+ return wd;
+}
/*******************************************************************
chown isn't used much but OS/2 doesn't have it
********************************************************************/
int sys_chown(char *fname,int uid,int 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
}
@@ -214,9 +482,155 @@ os/2 also doesn't have chroot
********************************************************************/
int sys_chroot(char *dname)
{
-#ifdef NO_CHROOT
- DEBUG(1,("Warning - chroot(%s) not done\n",dname));
+#ifndef HAVE_CHROOT
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: no chroot!\n"));
+ done=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(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(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(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 */
+}
+
+
+/**************************************************************************
+ Try and abstract process capabilities (for systems that have them).
+****************************************************************************/
+
+BOOL set_process_capability( uint32 cap_flag, BOOL enable )
+{
+#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
+ 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)));
+ return False;
+ }
+
+ DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+#endif
+ return True;
+}
+
+/**************************************************************************
+ Try and abstract inherited process capabilities (for systems that have them).
+****************************************************************************/
+
+BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
+{
+#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
+ 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)));
+ return False;
+ }
+
+ DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
+ }
+#endif
+ return True;
+}
+
+/**************************************************************************
+ 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
- return(chroot(dname));
+ DEBUG(0,("Error - no srandom function available !\n"));
+ exit(1);
#endif
}
diff --git a/source/lib/time.c b/source/lib/time.c
new file mode 100644
index 00000000000..529f0ceb447
--- /dev/null
+++ b/source/lib/time.c
@@ -0,0 +1,546 @@
+/*
+ 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 serverzone=0;
+int extra_time_offset = 0;
+
+extern int DEBUGLEVEL;
+
+#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
+
+
+
+/*******************************************************************
+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);
+
+}
+
+
+/*******************************************************************
+init the time differences
+********************************************************************/
+void TimeInit(void)
+{
+ 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));
+}
+
+
+/*******************************************************************
+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;} *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);
+ dst_table = (struct dst_table *)Realloc(dst_table,
+ sizeof(dst_table[0])*(i+1));
+ if (!dst_table) {
+ table_size = 0;
+ } else {
+ 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));
+}
+
+/****************************************************************************
+take an NTTIME structure, containing high / low time. convert to unix time.
+lkclXXXX this may need 2 SIVALs not a memcpy. we'll see...
+****************************************************************************/
+time_t interpret_nt_time(NTTIME *t)
+{
+ char data[8];
+ memcpy(data, t, sizeof(data));
+ return interpret_long_date(data);
+}
+
+
+#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)
+{
+ double d;
+ time_t ret;
+ uint32 tlow,thigh;
+ /* 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;
+
+ 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 (!(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 -= serverzone;
+ ret += LocTimeDiff(ret);
+
+ return(ret);
+}
+
+
+/****************************************************************************
+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)
+{
+ uint32 tlow,thigh;
+ double d;
+
+ if (t==0) {
+ SIVAL(p,0,0); SIVAL(p,4,0);
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= LocTimeDiff(t) - serverzone;
+
+ d = (double) (t);
+
+ d += TIME_FIXUP_CONSTANT;
+
+ d *= 1.0e7;
+
+ thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+
+ SIVAL(p,0,tlow);
+ SIVAL(p,4,thigh);
+}
+
+
+/****************************************************************************
+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(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);
+ if (!t)
+ return 0xFFFFFFFF;
+
+ 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 -= 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));
+#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(void )
+{
+ static fstring TimeBuf;
+ time_t t = time(NULL);
+ struct tm *tm = LocalTime(&t);
+
+ if (!tm) {
+ slprintf(TimeBuf,sizeof(TimeBuf)-1,"%ld seconds since the Epoch",(long)t);
+ } else {
+#ifdef HAVE_STRFTIME
+ strftime(TimeBuf,100,"%Y/%m/%d %T",tm);
+#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;
+}
+
diff --git a/source/lib/ufc.c b/source/lib/ufc.c
index 8417285821a..f464953498e 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
@@ -656,11 +657,11 @@ 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)
{ ufc_long *s;
@@ -702,7 +703,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)
+static ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
ufc_long l1, l2, r1, r2, itr;
{ int i;
long32 s, *k;
@@ -742,7 +743,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)
+static ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
ufc_long l1, l2, r1, r2, itr;
{ int i;
long64 l, r, s, *k;
@@ -777,6 +778,6 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr)
#else
-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..f56f7efce2e 100644
--- a/source/lib/username.c
+++ b/source/lib/username.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Username 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,18 +20,20 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
+/* internal functions */
+static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) (char *), int N);
+static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (char *), int N);
/****************************************************************************
-get a users home directory. tries as-is then lower case
+get a users home directory.
****************************************************************************/
char *get_home_dir(char *user)
{
static struct passwd *pass;
- pass = Get_Pwnam(user,False);
+ pass = Get_Pwnam(user, False);
if (!pass) return(NULL);
return(pass->pw_dir);
@@ -40,76 +42,109 @@ char *get_home_dir(char *user)
/*******************************************************************
map a username from a dos name to a unix name by looking in the username
-map
+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;
+ char *s;
+ pstring buf;
+ BOOL mapped_user = False;
- if (!*user) return;
+ if (!*user)
+ return False;
+
+ if (!*mapfile)
+ return False;
if (!initialised) {
*last_from = *last_to = 0;
initialised = True;
}
- if (strequal(user,last_to)) return;
+ if (strequal(user,last_to))
+ return False;
if (strequal(user,last_from)) {
DEBUG(3,("Mapped user %s to %s\n",user,last_to));
- strcpy(user,last_to);
- return;
+ fstrcpy(user,last_to);
+ return True;
}
f = fopen(mapfile,"r");
if (!f) {
DEBUG(0,("can't open username map %s\n",mapfile));
- return;
+ return False;
}
DEBUG(4,("Scanning username map %s\n",mapfile));
- depth++;
-
- for (; (s=fgets_slash(NULL,80,f)); free(s)) {
+ while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) {
char *unixname = s;
char *dosname = strchr(unixname,'=');
+ BOOL return_if_mapped = False;
+
+ if (!dosname)
+ continue;
- if (!dosname) continue;
*dosname++ = 0;
- while (isspace(*unixname)) unixname++;
- if (!*unixname || strchr("#;",*unixname)) continue;
+ while (isspace(*unixname))
+ unixname++;
+ if ('!' == *unixname) {
+ return_if_mapped = True;
+ unixname++;
+ while (*unixname && isspace(*unixname))
+ unixname++;
+ }
+
+ if (!*unixname || strchr("#;",*unixname))
+ continue;
{
int l = strlen(unixname);
while (l && isspace(unixname[l-1])) {
- unixname[l-1] = 0;
- l--;
+ unixname[l-1] = 0;
+ l--;
}
}
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);
+ mapped_user = True;
+ fstrcpy(last_from,user);
sscanf(unixname,"%s",user);
- StrnCpy(last_to,user,sizeof(last_to)-1);
+ fstrcpy(last_to,user);
+ if(return_if_mapped) {
+ fclose(f);
+ return True;
+ }
}
}
fclose(f);
- depth--;
+ /*
+ * 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)
{
@@ -118,7 +153,7 @@ static struct passwd *_Get_Pwnam(char *s)
ret = getpwnam(s);
if (ret)
{
-#ifdef GETPWANAM
+#ifdef HAVE_GETPWANAM
struct passwd_adjunct *pwret;
pwret = getpwanam(s);
if (pwret)
@@ -137,11 +172,13 @@ static struct passwd *_Get_Pwnam(char *s)
/****************************************************************************
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!
+Note that this can change user!
****************************************************************************/
struct passwd *Get_Pwnam(char *user,BOOL allow_change)
{
fstring user2;
+ int last_char;
+ int usernamelevel = lp_usernamelevel();
struct passwd *ret;
@@ -154,8 +191,6 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change)
user = &user2[0];
}
- map_username(user);
-
ret = _Get_Pwnam(user);
if (ret) return(ret);
@@ -173,74 +208,216 @@ struct passwd *Get_Pwnam(char *user,BOOL allow_change)
ret = _Get_Pwnam(user);
if (ret) return(ret);
+ /* try with last letter capitalised */
+ strlower(user);
+ last_char = strlen(user)-1;
+ user[last_char] = toupper(user[last_char]);
+ ret = _Get_Pwnam(user);
+ if (ret) return(ret);
+
+ /* try all combinations up to usernamelevel */
+ strlower(user);
+ ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel);
+ if (ret) return(ret);
+
if (allow_change)
- strcpy(user,user2);
+ fstrcpy(user,user2);
return(NULL);
}
+/****************************************************************************
+check if a user is in a netgroup user list
+****************************************************************************/
+static BOOL user_in_netgroup_list(char *user,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"));
+ }
+ else
+ {
+ 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 UNIX user list
+****************************************************************************/
+static BOOL user_in_group_list(char *user,char *gname)
+{
+#ifdef HAVE_GETGRNAM
+ struct group *gptr;
+ char **member;
+ struct passwd *pass = Get_Pwnam(user,False);
+
+ if (pass)
+ {
+ gptr = getgrgid(pass->pw_gid);
+ if (gptr && strequal(gptr->gr_name,gname))
+ return(True);
+ }
+
+ gptr = (struct group *)getgrnam(gname);
+
+ if (gptr)
+ {
+ member = gptr->gr_mem;
+ while (member && *member)
+ {
+ if (strequal(*member,user))
+ return(True);
+ member++;
+ }
+ }
+#endif /* HAVE_GETGRNAM */
+ return False;
+}
/****************************************************************************
-check if a user is in a user list
+check if a user is in a user list - can check combinations of UNIX
+and netgroup lists.
****************************************************************************/
BOOL user_in_list(char *user,char *list)
{
pstring tok;
char *p=list;
- while (next_token(&p,tok,LIST_SEP))
+ while (next_token(&p,tok,LIST_SEP, sizeof(tok)))
+ {
+ /*
+ * Check raw username.
+ */
+ if (strequal(user,tok))
+ return(True);
+
+ /*
+ * Now check to see if any combination
+ * of UNIX and netgroups has been specified.
+ */
+
+ if(*tok == '@')
+ {
+ /*
+ * Old behaviour. Check netgroup list
+ * followed by UNIX list.
+ */
+ if(user_in_netgroup_list(user,&tok[1]))
+ return True;
+ if(user_in_group_list(user,&tok[1]))
+ return True;
+ }
+ else if (*tok == '+')
+ {
+ if(tok[1] == '&')
+ {
+ /*
+ * Search UNIX list followed by netgroup.
+ */
+ if(user_in_group_list(user,&tok[2]))
+ return True;
+ if(user_in_netgroup_list(user,&tok[2]))
+ return True;
+ }
+ else
+ {
+ /*
+ * Just search UNIX list.
+ */
+ if(user_in_group_list(user,&tok[1]))
+ return True;
+ }
+ }
+ else if (*tok == '&')
{
- if (strequal(user,tok))
- return(True);
+ if(tok[1] == '&')
+ {
+ /*
+ * Search netgroup list followed by UNIX list.
+ */
+ if(user_in_netgroup_list(user,&tok[2]))
+ return True;
+ if(user_in_group_list(user,&tok[2]))
+ return True;
+ }
+ else
+ {
+ /*
+ * Just search netgroup list.
+ */
+ if(user_in_netgroup_list(user,&tok[1]))
+ return True;
+ }
+ }
+ }
+ return(False);
+}
-#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);
- }
+/* 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)(char *),int N)
+{
+ int len = strlen(s);
+ int i;
+ struct passwd *ret;
+
+#ifdef PASSWORD_LENGTH
+ len = MIN(len,PASSWORD_LENGTH);
#endif
+ if (N <= 0 || offset >= len)
+ return(fn(s));
-#if HAVE_GETGRNAM
- if (*tok == '@')
- {
- struct group *gptr;
- char **member;
- struct passwd *pass = Get_Pwnam(user,False);
-
- if (pass) {
- gptr = getgrgid(pass->pw_gid);
- if (gptr && strequal(gptr->gr_name,&tok[1]))
- return(True);
- }
-
- gptr = (struct group *)getgrnam(&tok[1]);
-
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- if (strequal(*member,user))
- return(True);
- member++;
- }
- }
- }
-#endif
+
+ for (i=offset;i<(len-(N-1));i++)
+
+ {
+ char c = s[i];
+ if (!islower(c)) continue;
+ s[i] = toupper(c);
+ ret = uname_string_combinations2(s,i+1,fn,N-1);
+ if(ret) return(ret);
+ s[i] = c;
}
- return(False);
+ 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)(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);
+}
diff --git a/source/lib/util.c b/source/lib/util.c
index 7bd6298c4ca..8561c4f3f4a 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
- 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,41 +20,44 @@
*/
#include "includes.h"
-#include "loadparm.h"
+
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
+#ifdef WITH_NISPLUS_HOME
+#include <rpcsvc/nis.h>
+#else
+#include "rpcsvc/ypclnt.h"
+#endif
+#endif
+
+#ifdef WITH_SSL
+#include <ssl.h>
+#undef Realloc /* SSLeay defines this and samba has a function of this name */
+extern SSL *ssl;
+extern int sslFd;
+#endif /* WITH_SSL */
pstring scope = "";
-int DEBUGLEVEL = 1;
+extern int DEBUGLEVEL;
BOOL passive = False;
int Protocol = PROTOCOL_COREPLUS;
-int serverzone=0;
-
/* a default finfo structure to ensure all fields are sensible */
file_info def_finfo = {-1,0,0,0,0,0,0,""};
-/* these are some file handles where debug info will be stored */
-FILE *dbf = NULL;
-
/* the client file descriptor */
int Client = -1;
-/* info on the client */
-struct from_host Client_info=
-{"UNKNOWN","0.0.0.0",NULL};
-
/* the last IP received from */
struct in_addr lastip;
/* the last port received from */
int lastport=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 +66,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;
@@ -81,448 +77,39 @@ BOOL case_mangle;
fstring remote_machine="";
fstring local_machine="";
fstring remote_arch="UNKNOWN";
+static enum remote_arch_types ra_type = RA_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;
- }
-}
+pstring sesssetup_user="";
+pstring samlogon_user="";
-BOOL append_log=False;
+BOOL sam_logon_in_ssb = False;
+pstring global_myname = "";
+fstring global_myworkgroup = "";
+char **my_netbios_names;
-/****************************************************************************
-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());
+int smb_read_error = 0;
- 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
+static char *filename_dos(char *path,char *buf);
- 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)
+ find a suitable temporary directory. The result should be copied immediately
+ as it may be overwritten by a subsequent call
+ ****************************************************************************/
+char *tmpdir(void)
{
-#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
-}
-
-/*******************************************************************
-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));
-*/
+ char *p;
+ if ((p = getenv("TMPDIR"))) {
+ return p;
}
-#endif
-
- return((is_dst?60*60:0) - (extra_time_offset*60));
+ return "/tmp";
}
-/****************************************************************************
-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));
-}
/****************************************************************************
@@ -544,10 +131,11 @@ static char *last_ptr=NULL;
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)
+BOOL next_token(char **ptr,char *buff,char *sep, int bufsize)
{
char *s;
BOOL quoted;
+ int len=1;
if (!ptr) ptr = &last_ptr;
if (!ptr) return(False);
@@ -564,12 +152,14 @@ BOOL next_token(char **ptr,char *buff,char *sep)
if (! *s) return(False);
/* copy over the token */
- for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++)
+ for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++)
{
- if (*s == '\"')
- quoted = !quoted;
- else
- *buff++ = *s;
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
}
*ptr = (*s) ? s+1 : s;
@@ -616,71 +206,10 @@ char **toktocliplist(int *ctok, char *sep)
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)
-{
- 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
-
-
/****************************************************************************
prompte a dptr (to make it recently used)
****************************************************************************/
-void array_promote(char *array,int elsize,int element)
+static void array_promote(char *array,int elsize,int element)
{
char *p;
if (element == 0)
@@ -733,6 +262,12 @@ struct
#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}};
@@ -742,9 +277,9 @@ set user socket options
****************************************************************************/
void set_socket_options(int fd, char *options)
{
- string tok;
+ fstring tok;
- while (next_token(&options,tok," \t,"))
+ while (next_token(&options,tok," \t,", sizeof(tok)))
{
int ret=0,i;
int value = 1;
@@ -800,50 +335,28 @@ void set_socket_options(int fd, char *options)
****************************************************************************/
void close_sockets(void )
{
+#ifdef WITH_SSL
+ sslutil_disconnect(Client);
+#endif /* WITH_SSL */
+
close(Client);
Client = 0;
}
/****************************************************************************
- 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);
-}
-
-/****************************************************************************
determine whether we are in the specified group
****************************************************************************/
-BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups)
+BOOL in_group(gid_t group, int current_gid, int ngroups, GID_T *groups)
{
- int i;
+ int i;
- if (group == current_gid) return(True);
+ if (group == current_gid) return(True);
- for (i=0;i<ngroups;i++)
- if (group == groups[i])
- return(True);
+ for (i=0;i<ngroups;i++)
+ if (group == groups[i])
+ return(True);
- return(False);
+ return(False);
}
/****************************************************************************
@@ -853,13 +366,8 @@ 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
+ SMB_ASSERT(dest && src);
if (!dest) return(NULL);
if (!src) {
@@ -873,7 +381,7 @@ char *StrCpy(char *dest,char *src)
/****************************************************************************
line strncpy but always null terminates. Make sure there is room!
****************************************************************************/
-char *StrnCpy(char *dest,const char *src,int n)
+char *StrnCpy(char *dest,char *src,int n)
{
char *d = dest;
if (!dest) return(NULL);
@@ -896,6 +404,46 @@ void putip(void *dest,void *src)
}
+#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;
+}
+
+
/****************************************************************************
interpret the weird netbios "name". Return the name type
****************************************************************************/
@@ -938,58 +486,71 @@ static int name_interpret(char *in,char *out)
/****************************************************************************
mangle a name into netbios format
+
+ Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
****************************************************************************/
-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;
+int name_mangle( char *In, char *Out, char name_type )
+ {
+ int i;
+ int c;
+ int len;
+ char buf[20];
+ char *p = Out;
+
+ /* Safely copy the input string, In, into buf[]. */
+ (void)memset( buf, 0, 20 );
+ if( '*' == In[0] )
+ buf[0] = '*';
+ else
+ (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type );
- 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);
- }
+ /* Place the length of the first field into the output buffer. */
+ p[0] = 32;
+ p++;
- *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)
+ /* Now convert the name to the rfc1001/1002 format. */
+ for( i = 0; i < 16; i++ )
{
- 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 == '.');
+ c = toupper( buf[i] );
+ p[i*2] = ( (c >> 4) & 0x000F ) + 'A';
+ p[(i*2)+1] = (c & 0x000F) + 'A';
+ }
+ p += 32;
+ p[0] = '\0';
+
+ /* Add the scope string. */
+ for( i = 0, len = 0; NULL != scope; i++, len++ )
+ {
+ switch( 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 = 0;
+ break;
+ default:
+ p[len+1] = scope[i];
+ break;
+ }
}
- *out = 0;
- return(name_len(Out));
-}
+ return( name_len(Out) );
+ } /* name_mangle */
/*******************************************************************
check if a file exists
********************************************************************/
-BOOL file_exist(char *fname,struct stat *sbuf)
+BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf)
{
- struct stat st;
+ SMB_STRUCT_STAT st;
if (!sbuf) sbuf = &st;
- if (sys_stat(fname,sbuf) != 0)
+ if (dos_stat(fname,sbuf) != 0)
return(False);
return(S_ISREG(sbuf->st_mode));
@@ -1000,9 +561,9 @@ check a files mod time
********************************************************************/
time_t file_modtime(char *fname)
{
- struct stat st;
+ SMB_STRUCT_STAT st;
- if (sys_stat(fname,&st) != 0)
+ if (dos_stat(fname,&st) != 0)
return(0);
return(st.st_mtime);
@@ -1011,196 +572,48 @@ time_t file_modtime(char *fname)
/*******************************************************************
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)
+ if (dos_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 file_size(char *file_name)
{
- struct stat buf;
+ SMB_STRUCT_STAT buf;
buf.st_size = 0;
- sys_stat(file_name,&buf);
+ dos_stat(file_name,&buf);
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)
{
- 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);
}
@@ -1211,10 +624,72 @@ char *attrib_string(int mode)
********************************************************************/
int StrCaseCmp(char *s, char *t)
{
- for (; tolower(*s) == tolower(*t); ++s, ++t)
- if (!*s) return 0;
+ /* compare until we run out of string, either t or s, or find a difference */
+ /* We *must* use toupper rather than tolower here due to the
+ asynchronous upper to lower mapping.
+ */
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ int diff;
+ for (;;)
+ {
+ if (!*s || !*t)
+ return toupper (*s) - toupper (*t);
+ else if (is_sj_alph (*s) && is_sj_alph (*t))
+ {
+ diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ }
+ else if (is_shift_jis (*s) && is_shift_jis (*t))
+ {
+ diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+ if (diff)
+ return diff;
+ diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ }
+ else if (is_shift_jis (*s))
+ return 1;
+ else if (is_shift_jis (*t))
+ return -1;
+ else
+ {
+ diff = toupper (*s) - toupper (*t);
+ if (diff)
+ return diff;
+ s++;
+ t++;
+ }
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ while (*s && *t && toupper(*s) == toupper(*t))
+ {
+ s++;
+ t++;
+ }
- return tolower(*s) - tolower(*t);
+ return(toupper(*s) - toupper(*t));
+ }
}
/*******************************************************************
@@ -1222,19 +697,89 @@ int StrCaseCmp(char *s, char *t)
********************************************************************/
int StrnCaseCmp(char *s, char *t, int n)
{
- while (n-- && *s && *t) {
- if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
- s++; t++;
+ /* compare until we run out of string, either t or s, or chars */
+ /* We *must* use toupper rather than tolower here due to the
+ asynchronous upper to lower mapping.
+ */
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ int diff;
+ for (;n > 0;)
+ {
+ if (!*s || !*t)
+ return toupper (*s) - toupper (*t);
+ else if (is_sj_alph (*s) && is_sj_alph (*t))
+ {
+ diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ n -= 2;
+ }
+ else if (is_shift_jis (*s) && is_shift_jis (*t))
+ {
+ diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+ if (diff)
+ return diff;
+ diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+ if (diff)
+ return diff;
+ s += 2;
+ t += 2;
+ n -= 2;
+ }
+ else if (is_shift_jis (*s))
+ return 1;
+ else if (is_shift_jis (*t))
+ return -1;
+ else
+ {
+ diff = toupper (*s) - toupper (*t);
+ if (diff)
+ return diff;
+ s++;
+ t++;
+ n--;
+ }
+ }
+ return 0;
}
- if (n) return(tolower(*s) - tolower(*t));
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ while (n && *s && *t && toupper(*s) == toupper(*t))
+ {
+ s++;
+ t++;
+ n--;
+ }
- return(0);
+ /* not run out of chars - strings are different lengths */
+ if (n)
+ return(toupper(*s) - toupper(*t));
+
+ /* identical up to where we run out of chars,
+ and strings are same length */
+ return(0);
+ }
}
/*******************************************************************
compare 2 strings
********************************************************************/
-BOOL strequal(char *s1,char *s2)
+BOOL strequal(char *s1, char *s2)
{
if (s1 == s2) return(True);
if (!s1 || !s2) return(False);
@@ -1271,23 +816,51 @@ BOOL strcsequal(char *s1,char *s2)
void strlower(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (isupper(*s))
- *s = tolower(*s);
- s++;
- }
-#else
- if (isupper(*s))
- *s = tolower(*s);
- s++;
-#endif /* KANJI */
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ {
+ if (is_sj_upper (s[0], s[1]))
+ s[1] = sj_tolower2 (s[1]);
+ s += 2;
+ }
+ else if (is_kana (*s))
+ {
+ s++;
+ }
+ else
+ {
+ if (isupper(*s))
+ *s = tolower(*s);
+ s++;
+ }
}
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ int skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ s += skip;
+ else
+ {
+ if (isupper(*s))
+ *s = tolower(*s);
+ s++;
+ }
+ }
+ }
}
/*******************************************************************
@@ -1296,23 +869,51 @@ void strlower(char *s)
void strupper(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
{
-#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
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ {
+ if (is_sj_lower (s[0], s[1]))
+ s[1] = sj_toupper2 (s[1]);
+ s += 2;
+ }
+ else if (is_kana (*s))
+ {
+ s++;
+ }
+ else
+ {
+ if (islower(*s))
+ *s = toupper(*s);
+ s++;
+ }
}
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ int skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ s += skip;
+ else
+ {
+ if (islower(*s))
+ *s = toupper(*s);
+ s++;
+ }
+ }
+ }
}
/*******************************************************************
@@ -1343,24 +944,19 @@ BOOL strisnormal(char *s)
****************************************************************************/
void string_replace(char *s,char oldc,char newc)
{
+ int skip;
while (*s)
+ {
+ skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ s += skip;
+ else
{
-#ifdef KANJI
- if (is_shift_jis (*s)) {
- s += 2;
- } else if (is_kana (*s)) {
- s++;
- } else {
- if (oldc == *s)
- *s = newc;
- s++;
- }
-#else
if (oldc == *s)
- *s = newc;
+ *s = newc;
s++;
-#endif /* KANJI */
}
+ }
}
/****************************************************************************
@@ -1368,18 +964,7 @@ void string_replace(char *s,char oldc,char newc)
****************************************************************************/
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);
- }
}
/****************************************************************************
@@ -1387,49 +972,53 @@ void unix_format(char *fname)
****************************************************************************/
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;
+ 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)));
+ }
- 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"));
-}
+ bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
+ DEBUG(5,("smb_bcc=%d\n",bcc));
+
+ if (DEBUGLEVEL < 10) return;
+
+ if (DEBUGLEVEL < 50)
+ {
+ bcc = MIN(bcc, 512);
+ }
+
+ dump_data(10, smb_buf(buf), bcc);
+}
/*******************************************************************
return the length of an smb packet
********************************************************************/
@@ -1478,7 +1067,7 @@ int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
/*******************************************************************
return the number of smb words
********************************************************************/
-int smb_numwords(char *buf)
+static int smb_numwords(char *buf)
{
return (CVAL(buf,smb_wct));
}
@@ -1494,7 +1083,7 @@ int smb_buflen(char *buf)
/*******************************************************************
return a pointer to the smb_buf data area
********************************************************************/
-int smb_buf_ofs(char *buf)
+static int smb_buf_ofs(char *buf)
{
return (smb_size + CVAL(buf,smb_wct)*2);
}
@@ -1512,7 +1101,7 @@ return the SMB offset into an SMB buffer
********************************************************************/
int smb_offset(char *p,char *buf)
{
- return(PTR_DIFF(p,buf+4));
+ return(PTR_DIFF(p,buf+4) + chain_size);
}
@@ -1532,23 +1121,30 @@ 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))
+ size_t front_len = (front && *front) ? strlen(front) : 0;
+ size_t back_len = (back && *back) ? strlen(back) : 0;
+ size_t s_len;
+
+ while (front_len && strncmp(s, front, front_len) == 0)
+ {
+ char *p = s;
+ ret = True;
+ while (1)
{
- ret = True;
- s[strlen(s)-strlen(back)] = 0;
+ if (!(*p = p[front_len]))
+ break;
+ p++;
}
+ }
+
+ s_len = strlen(s);
+ while (back_len && s_len >= back_len &&
+ (strncmp(s + s_len - back_len, back, back_len)==0))
+ {
+ ret = True;
+ s[s_len - back_len] = 0;
+ s_len = strlen(s);
+ }
return(ret);
}
@@ -1570,13 +1166,13 @@ void dos_clean_name(char *s)
pstring s1;
*p = 0;
- strcpy(s1,p+3);
+ pstrcpy(s1,p+3);
if ((p=strrchr(s,'\\')) != NULL)
*p = 0;
else
*s = 0;
- strcat(s,s1);
+ pstrcat(s,s1);
}
trim_string(s,NULL,"\\..");
@@ -1596,18 +1192,25 @@ void unix_clean_name(char *s)
/* remove any double slashes */
string_sub(s, "//","/");
+ /* 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)
*p = 0;
else
*s = 0;
- strcat(s,s1);
+ pstrcat(s,s1);
}
trim_string(s,NULL,"/..");
@@ -1626,122 +1229,110 @@ int ChDir(char *path)
if (*path == '/' && strcsequal(LastDir,path)) return(0);
DEBUG(3,("chdir to %s\n",path));
- res = sys_chdir(path);
+ res = dos_chdir(path);
if (!res)
- strcpy(LastDir,path);
+ pstrcpy(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;
+ 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 *text; /* The pathname in DOS format. */
BOOL valid;
} ino_list[MAX_GETWDCACHE];
BOOL use_getwd_cache=True;
/*******************************************************************
- return the absolute current directory path
+ return the absolute current directory path - given a UNIX pathname.
+ Note that this path is returned in DOS format, not UNIX
+ format.
********************************************************************/
char *GetWd(char *str)
{
pstring s;
static BOOL getwd_cache_init = False;
- struct stat st, st2;
+ SMB_STRUCT_STAT st, st2;
int i;
*s = 0;
if (!use_getwd_cache)
- return(Dumb_GetWd(str));
+ return(dos_getwd(str));
/* init the cache */
if (!getwd_cache_init)
+ {
+ getwd_cache_init = True;
+ for (i=0;i<MAX_GETWDCACHE;i++)
{
- getwd_cache_init = True;
- for (i=0;i<MAX_GETWDCACHE;i++)
- {
- string_init(&ino_list[i].text,"");
- ino_list[i].valid = False;
- }
+ 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));
- }
+ if (dos_stat(".",&st) == -1)
+ {
+ DEBUG(0,("Very strange, couldn't stat \".\"\n"));
+ return(dos_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 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;
- }
- }
- }
+ if (st.st_ino == ino_list[i].inode &&
+ st.st_dev == ino_list[i].dev)
+ {
+ if (dos_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)
+ {
+ pstrcpy (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);
- }
+ if (!dos_getwd(s))
+ {
+ DEBUG(0,("Getwd failed, errno %s\n",strerror(errno)));
+ return (NULL);
+ }
- strcpy(str,s);
+ pstrcpy(str,s);
DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev));
@@ -1774,12 +1365,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
#else
pstring dir2;
pstring wd;
- pstring basename;
+ pstring base_name;
pstring newname;
char *p=NULL;
BOOL relative = (*s != '/');
- *dir2 = *wd = *basename = *newname = 0;
+ *dir2 = *wd = *base_name = *newname = 0;
if (widelinks)
{
@@ -1790,6 +1381,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
DEBUG(3,("Illegal file name? (%s)\n",s));
return(False);
}
+
+ if (strlen(s) == 0)
+ pstrcpy(s,"./");
+
return(True);
}
@@ -1798,8 +1393,8 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
/* remove any double slashes */
string_sub(s,"//","/");
- strcpy(basename,s);
- p = strrchr(basename,'/');
+ pstrcpy(base_name,s);
+ p = strrchr(base_name,'/');
if (!p)
return(True);
@@ -1824,7 +1419,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
}
- if (p && (p != basename))
+ if (p && (p != base_name))
{
*p = 0;
if (strcmp(p+1,".")==0)
@@ -1833,10 +1428,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
*p = '/';
}
- if (ChDir(basename) != 0)
+ if (ChDir(base_name) != 0)
{
ChDir(wd);
- DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename));
+ DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name));
return(False);
}
@@ -1847,10 +1442,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
return(False);
}
- if (p && (p != basename))
+ if (p && (p != base_name))
{
- strcat(newname,"/");
- strcat(newname,p+1);
+ pstrcat(newname,"/");
+ pstrcat(newname,p+1);
}
{
@@ -1868,18 +1463,18 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
if (relative)
{
if (newname[l] == '/')
- strcpy(s,newname + l + 1);
+ pstrcpy(s,newname + l + 1);
else
- strcpy(s,newname+l);
+ pstrcpy(s,newname+l);
}
else
- strcpy(s,newname);
+ pstrcpy(s,newname);
}
ChDir(wd);
if (strlen(s) == 0)
- strcpy(s,"./");
+ pstrcpy(s,"./");
DEBUG(3,("reduced to %s\n",s));
return(True);
@@ -1897,14 +1492,34 @@ static void expand_one(char *Mask,int len)
int lfill = (len+1) - strlen(Mask);
int l1= (p1 - Mask);
pstring tmp;
- strcpy(tmp,Mask);
+ pstrcpy(tmp,Mask);
memset(tmp+l1,'?',lfill);
- strcpy(tmp + l1 + lfill,Mask + l1 + 1);
- strcpy(Mask,tmp);
+ pstrcpy(tmp + l1 + lfill,Mask + l1 + 1);
+ pstrcpy(Mask,tmp);
}
}
/****************************************************************************
+parse out a directory name from a path name. Assumes dos style filenames.
+****************************************************************************/
+static char *dirname_dos(char *path,char *buf)
+{
+ char *p = strrchr(path,'\\');
+
+ if (!p)
+ pstrcpy(buf,path);
+ else
+ {
+ *p = 0;
+ pstrcpy(buf,path);
+ *p = '\\';
+ }
+
+ return(buf);
+}
+
+
+/****************************************************************************
expand a wildcard expression, replacing *s with ?s
****************************************************************************/
void expand_mask(char *Mask,BOOL doext)
@@ -1924,42 +1539,42 @@ void expand_mask(char *Mask,BOOL doext)
filename_dos(Mask,filepart);
- strcpy(mbeg,filepart);
+ pstrcpy(mbeg,filepart);
if ((p1 = strchr(mbeg,'.')) != NULL)
{
hasdot = True;
*p1 = 0;
p1++;
- strcpy(mext,p1);
+ pstrcpy(mext,p1);
}
else
{
- strcpy(mext,"");
+ pstrcpy(mext,"");
if (strlen(mbeg) > 8)
{
- strcpy(mext,mbeg + 8);
+ pstrcpy(mext,mbeg + 8);
mbeg[8] = 0;
}
}
if (*mbeg == 0)
- strcpy(mbeg,"????????");
+ pstrcpy(mbeg,"????????");
if ((*mext == 0) && doext && !hasdot)
- strcpy(mext,"???");
+ pstrcpy(mext,"???");
if (strequal(mbeg,"*") && *mext==0)
- strcpy(mext,"*");
+ pstrcpy(mext,"*");
/* expand *'s */
expand_one(mbeg,8);
if (*mext)
expand_one(mext,3);
- strcpy(Mask,dirpart);
- if (*dirpart || absolute) strcat(Mask,"\\");
- strcat(Mask,mbeg);
- strcat(Mask,".");
- strcat(Mask,mext);
+ pstrcpy(Mask,dirpart);
+ if (*dirpart || absolute) pstrcat(Mask,"\\");
+ pstrcat(Mask,mbeg);
+ pstrcat(Mask,".");
+ pstrcat(Mask,mext);
DEBUG(6,("Mask expanded to [%s]\n",Mask));
}
@@ -1971,21 +1586,44 @@ does a string have any uppercase chars in it?
BOOL strhasupper(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
{
-#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 */
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ s += 2;
+ else if (is_kana (*s))
+ s++;
+ else
+ {
+ if (isupper(*s))
+ return(True);
+ s++;
+ }
}
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ int skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ s += skip;
+ else {
+ if (isupper(*s))
+ return(True);
+ s++;
+ }
+ }
+ }
return(False);
}
@@ -1995,21 +1633,52 @@ does a string have any lowercase chars in it?
BOOL strhaslower(char *s)
{
while (*s)
+ {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
{
-#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 */
+ /* Win95 treats full width ascii characters as case sensitive. */
+ if (is_shift_jis (*s))
+ {
+ if (is_sj_upper (s[0], s[1]))
+ return(True);
+ if (is_sj_lower (s[0], s[1]))
+ return (True);
+ s += 2;
+ }
+ else if (is_kana (*s))
+ {
+ s++;
+ }
+ else
+ {
+ if (islower(*s))
+ return(True);
+ s++;
+ }
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ int skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ s += skip;
+ else {
+ if (islower(*s))
+ return(True);
+ s++;
+ }
}
+ }
return(False);
}
@@ -2019,12 +1688,47 @@ find the number of chars in a string
int count_chars(char *s,char c)
{
int count=0;
- while (*s)
+
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+ /*
+ * For completeness we should put in equivalent code for code pages
+ * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but
+ * doubt anyone wants Samba to behave differently from Win95 and WinNT
+ * here. They both treat full width ascii characters as case senstive
+ * filenames (ie. they don't do the work we do here).
+ * JRA.
+ */
+
+ if(lp_client_code_page() == KANJI_CODEPAGE)
+ {
+ /* Win95 treats full width ascii characters as case sensitive. */
+ while (*s)
{
- if (*s == c)
- count++;
- s++;
+ if (is_shift_jis (*s))
+ s += 2;
+ else
+ {
+ if (*s == c)
+ count++;
+ s++;
+ }
}
+ }
+ else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+ {
+ while (*s)
+ {
+ int skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ s += skip;
+ else {
+ if (*s == c)
+ count++;
+ s++;
+ }
+ }
+ }
return(count);
}
@@ -2032,12 +1736,12 @@ int count_chars(char *s,char c)
/****************************************************************************
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;
@@ -2057,7 +1761,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode
CVAL(buf,21) = mode;
put_dos_date(buf,22,date);
SSVAL(buf,26,size & 0xFFFF);
- SSVAL(buf,28,size >> 16);
+ SSVAL(buf,28,(size >> 16)&0xFFFF);
StrnCpy(buf+30,fname,12);
if (!case_sensitive)
strupper(buf+30);
@@ -2089,57 +1793,15 @@ 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
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
-int set_blocking(int fd, BOOL set)
+static int set_blocking(int fd, BOOL set)
{
-int val;
+ int val;
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
@@ -2150,7 +1812,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;
@@ -2162,178 +1824,158 @@ int val;
/****************************************************************************
-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
+write to a socket
****************************************************************************/
-static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2)
+ssize_t write_socket(int fd,char *buf,size_t len)
{
- int usecdiff = val1->tv_usec - val2->tv_usec;
- int secdiff = val1->tv_sec - val2->tv_sec;
- if(usecdiff < 0) {
- usecdiff = 1000000 + usecdiff;
- secdiff--;
+ ssize_t 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));
+ if(ret <= 0)
+ DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n",
+ len, fd, strerror(errno) ));
+
+ return(ret);
+}
+
+/****************************************************************************
+read from a socket
+****************************************************************************/
+ssize_t read_udp_socket(int fd,char *buf,size_t len)
+{
+ ssize_t ret;
+ struct sockaddr_in sock;
+ int socklen;
+
+ socklen = sizeof(sock);
+ bzero((char *)&sock,socklen);
+ bzero((char *)&lastip,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);
}
- 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);
+
+ 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 device with a timout in msec.
mincount = if timeout, minimum to read before returning
maxcount = number to be read.
+time_out = timeout in milliseconds
****************************************************************************/
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact)
+
+ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
{
fd_set fds;
int selrtn;
- int readret;
- int nread = 0;
- struct timeval timeout, tval1, tval2, tvaldiff;
- int error_limit = 5;
+ ssize_t readret;
+ size_t nread = 0;
+ struct timeval timeout;
/* just checking .... */
if (maxcnt <= 0) return(0);
- if(time_out == -2)
- time_out = DEFAULT_PIPE_TIMEOUT;
+ smb_read_error = 0;
/* Blocking read */
- if(time_out < 0) {
+ if (time_out <= 0) {
if (mincnt == 0) mincnt = maxcnt;
- while (nread < mincnt)
- {
- readret = read(fd, buf + nread, maxcnt - nread);
- if (readret <= 0) return(nread);
- nread += readret;
+ 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) {
+ smb_read_error = READ_EOF;
+ return -1;
}
- return(nread);
+
+ if (readret == -1) {
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ nread += readret;
+ }
+ return((ssize_t)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 */
+ 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_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);
- }
+ timeout.tv_sec = (time_t)(time_out / 1000);
+ timeout.tv_usec = (long)(1000 * (time_out % 1000));
- 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;
+ for (nread=0; nread < mincnt; )
+ {
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
- /* 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);
+ selrtn = sys_select(fd+1,&fds,&timeout);
+
+ /* Check if error */
+ if(selrtn == -1) {
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
- if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0)
- break; /* We timed out */
- }
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ smb_read_error = READ_TIMEOUT;
+ return -1;
+ }
- /* Save the time of day as we need to do the select
- again (saves a system call) */
- tval1 = tval2;
+#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 */
- /* Return the number we got */
- return(nread);
-}
-
-/****************************************************************************
-read data from the client. Maxtime is in milliseconds
-****************************************************************************/
-int read_max_udp(int fd,char *buffer,int bufsize,int maxtime)
-{
- 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;
+ if (readret == 0) {
+ /* we got EOF on the file descriptor */
+ smb_read_error = READ_EOF;
+ return -1;
+ }
- nread = read_udp_socket(fd, buffer, bufsize);
+ if (readret == -1) {
+ /* the descriptor is probably dead */
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ nread += readret;
+ }
- /* return the number got */
- return(nread);
+ /* Return the number we got */
+ return((ssize_t)nread);
}
/*******************************************************************
@@ -2364,184 +2006,92 @@ BOOL send_keepalive(int client)
/****************************************************************************
read data from the client, reading exactly N bytes.
****************************************************************************/
-int read_data(int fd,char *buffer,int N)
+ssize_t read_data(int fd,char *buffer,size_t N)
{
- int ret;
- int total=0;
+ 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);
-
- /* this is for portability */
- if (ret < 0)
- errno = EBADF;
-
- if (ret <= 0)
- return total;
- total += ret;
}
- return total;
-}
+#else /* WITH_SSL */
+ ret = read(fd,buffer + total,N - total);
+#endif /* WITH_SSL */
-
-/****************************************************************************
- write data to a fd
-****************************************************************************/
-int write_data(int fd,char *buffer,int N)
-{
- int total=0;
- int ret;
-
- while (total < N)
+ if (ret == 0)
{
- ret = write(fd,buffer + total,N - total);
-
- if (ret <= 0)
- return total;
-
- total += ret;
+ smb_read_error = READ_EOF;
+ return 0;
}
- return total;
-}
-
-
-/* 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
-****************************************************************************/
-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)
+ if (ret == -1)
{
- 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));
+ smb_read_error = READ_ERROR;
+ return -1;
}
-
- if (ret == num) {
- predict_skip = True;
- } else {
- predict_skip = False;
-
- /* prepare the next prediction */
- rp_predict_fd = fd;
- rp_predict_offset = offset + num;
- rp_predict_length = num;
+ total += ret;
}
-
- if (ret < 0) ret = 0;
-
- return(ret);
+ return (ssize_t)total;
}
+
/****************************************************************************
-pre-read some data
+ write data to a fd
****************************************************************************/
-void do_read_prediction()
+ssize_t write_data(int fd,char *buffer,size_t N)
{
- 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;
+ size_t total=0;
+ ssize_t ret;
- 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;
- }
+ 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 (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;
-}
+ if (ret == -1) return -1;
+ if (ret == 0) return total;
-/****************************************************************************
-invalidate read-prediction on a fd
-****************************************************************************/
-void invalidate_read_prediction(int fd)
-{
- if (rp_fd == fd)
- rp_fd = -1;
- if (rp_predict_fd == fd)
- rp_predict_fd = -1;
+ total += ret;
+ }
+ return (ssize_t)total;
}
/****************************************************************************
transfer some data between two fd's
****************************************************************************/
-int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
+SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n,char *header,int headlen,int align)
{
static char *buf=NULL;
+ static int size=0;
char *buf1,*abuf;
- static int size = 0;
- int total = 0;
+ SMB_OFF_T total = 0;
- DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
+ DEBUG(4,("transfer_file n=%.0f (head=%d) called\n",(double)n,headlen));
- if ((size < ReadSize) && buf) {
- free(buf);
- buf = NULL;
+ if (size == 0) {
+ size = lp_readsize();
+ size = MAX(size,1024);
}
- 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);
@@ -2553,159 +2103,195 @@ int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
n += headlen;
while (n > 0)
- {
- int s = MIN(n,size);
- int ret,ret2=0;
+ {
+ int s = (int)MIN(n,(SMB_OFF_T)size);
+ int ret,ret2=0;
- ret = 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 >= 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 (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 (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;
+ 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
+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.
****************************************************************************/
-int read_smb_length(int fd,char *inbuf,int timeout)
+static ssize_t read_smb_length_return_keepalive(int fd,char *inbuf,unsigned int timeout)
{
- char *buffer;
- char buf[4];
- int len=0, msg_type;
- BOOL ok=False;
-
- if (inbuf)
- buffer = inbuf;
- else
- buffer = buf;
+ ssize_t len=0;
+ int msg_type;
+ BOOL ok = False;
while (!ok)
- {
- if (timeout > 0)
- ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
- else
- ok = (read_data(fd,buffer,4) == 4);
+ {
+ if (timeout > 0)
+ ok = (read_with_timeout(fd,inbuf,4,4,timeout) == 4);
+ else
+ ok = (read_data(fd,inbuf,4) == 4);
- 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);
- }
- }
+ if (!ok)
+ return(-1);
- len = smb_len(buffer);
- msg_type = CVAL(buffer,0);
+ len = smb_len(inbuf);
+ msg_type = CVAL(inbuf,0);
- if (msg_type == 0x85)
- {
- DEBUG(5,( "Got keepalive packet\n"));
- ok = False;
- }
- }
+ if (msg_type == 0x85)
+ 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) != 0x85)
+ break;
+ }
+
+ return len;
+}
/****************************************************************************
- read an smb from a fd and return it's length
-The timeout is in milli seconds
+ 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,int timeout)
+BOOL receive_smb(int fd,char *buffer, unsigned int timeout)
{
- int len;
- BOOL ok;
+ ssize_t len,ret;
+
+ smb_read_error = 0;
bzero(buffer,smb_size + 100);
- len = read_smb_length(fd,buffer,timeout);
- if (len == -1)
+ len = read_smb_length_return_keepalive(fd,buffer,timeout);
+ if (len < 0)
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();
+ if (len > BUFFER_SIZE) {
+ DEBUG(0,("Invalid packet length! (%d bytes).\n",len));
+ if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
exit(1);
- }
+ }
+ if(len > 0) {
+ ret = read_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 == False)
+ return ret;
+
+ /* Ignore session keepalive packets. */
+ if(CVAL(buffer,0) != 0x85)
+ break;
+ }
+ return ret;
+}
/****************************************************************************
send an smb to a fd
****************************************************************************/
BOOL send_smb(int fd,char *buffer)
{
- int len;
- int ret,nwritten=0;
+ 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)
{
- 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;
+ DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret));
+ close_sockets();
+ exit(1);
}
-
+ nwritten += ret;
+ }
return True;
}
@@ -2714,7 +2300,7 @@ BOOL send_smb(int fd,char *buffer)
/****************************************************************************
find a pointer to a netbios name
****************************************************************************/
-char *name_ptr(char *buf,int ofs)
+static char *name_ptr(char *buf,int ofs)
{
unsigned char c = *(unsigned char *)(buf+ofs);
@@ -2739,24 +2325,30 @@ int name_extract(char *buf,int ofs,char *name)
{
char *p = name_ptr(buf,ofs);
int d = PTR_DIFF(p,buf+ofs);
- strcpy(name,"");
+ 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 *s)
+int name_len( char *s )
{
- char *s0=s;
- unsigned char c = *(unsigned char *)s;
- if ((c & 0xC0) == 0xC0)
+ int len;
+
+ /* If the two high bits of the byte are set, return 2. */
+ if( 0xC0 == (*(unsigned char *)s & 0xC0) )
return(2);
- while (*s) s += (*s)+1;
- return(PTR_DIFF(s,s0)+1);
-}
+
+ /* Add up the length bytes. */
+ for( len = 1; (*s); s += (*s) + 1 )
+ {
+ len += *s + 1;
+ }
+
+ return( len );
+} /* name_len */
/****************************************************************************
send a single packet to a port on another machine
@@ -2792,8 +2384,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
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));
+ DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+ inet_ntoa(ip),port,strerror(errno)));
close(out_fd);
return(ret);
@@ -2802,7 +2394,7 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
/*******************************************************************
sleep for a specified number of milliseconds
********************************************************************/
-void msleep(int t)
+static void msleep(int t)
{
int tdiff=0;
struct timeval tval,t1,t2;
@@ -2817,7 +2409,7 @@ void msleep(int t)
FD_ZERO(&fds);
errno = 0;
- sys_select(&fds,&tval);
+ sys_select(0,&fds,&tval);
GetTimeOfDay(&t2);
tdiff = TvalDiff(&t1,&t2);
@@ -2834,16 +2426,15 @@ BOOL in_list(char *s,char *list,BOOL casesensitive)
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);
- }
+ 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);
}
@@ -2863,16 +2454,24 @@ BOOL string_init(char **dest,char *src)
if (l == 0)
{
- if (!null_string)
- null_string = (char *)malloc(1);
-
- *null_string = 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);
- strcpy(*dest,src);
+ (*dest) = (char *)malloc(l+1);
+ if ((*dest) == NULL) {
+ DEBUG(0,("Out of memory in string_init\n"));
+ return False;
+ }
+
+ pstrcpy(*dest,src);
}
return(True);
}
@@ -2934,13 +2533,12 @@ BOOL string_sub(char *s,char *pattern,char *insert)
return(ret);
}
-
-
/*********************************************************
-* Recursive routine that is called by mask_match.
-* Does the actual matching.
+* Recursive routine that is called by unix_mask_match.
+* Does the actual matching. This is the 'original code'
+* used by the unix matcher.
*********************************************************/
-BOOL do_match(char *str, char *regexp, int case_sig)
+static BOOL unix_do_match(char *str, char *regexp, int case_sig)
{
char *p;
@@ -2959,7 +2557,7 @@ BOOL do_match(char *str, char *regexp, int case_sig)
while(*str) {
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
str++;
- if(do_match(str,p,case_sig))
+ if(unix_do_match(str,p,case_sig))
return True;
if(!*str)
return False;
@@ -3002,8 +2600,10 @@ BOOL do_match(char *str, char *regexp, int case_sig)
* Routine to match a given string with a regexp - uses
* simplified regexp that takes * and ? only. Case can be
* significant or not.
+* This is the 'original code' used by the unix matcher.
*********************************************************/
-BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
+
+static BOOL unix_mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
{
char *p;
pstring p1, p2;
@@ -3016,301 +2616,365 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
StrnCpy(p2,str,sizeof(pstring)-1);
if (!strchr(p2,'.')) {
- strcat(p2,".");
- }
-
-/*
- if (!strchr(p1,'.')) {
- strcat(p1,".");
+ pstrcat(p2,".");
}
-*/
-
-#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]);
+ (void)pstrcpy( &p[1], &p[2]);
if (strequal(p1,"*")) return(True);
- DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+ DEBUG(8,("unix_mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
if (trans2) {
- strcpy(ebase,p1);
- strcpy(sbase,p2);
+ fstrcpy(ebase,p1);
+ fstrcpy(sbase,p2);
} else {
if ((p=strrchr(p1,'.'))) {
*p = 0;
- strcpy(ebase,p1);
- strcpy(eext,p+1);
+ fstrcpy(ebase,p1);
+ fstrcpy(eext,p+1);
} else {
- strcpy(ebase,p1);
+ fstrcpy(ebase,p1);
eext[0] = 0;
}
if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
*p = 0;
- strcpy(sbase,p2);
- strcpy(sext,p+1);
+ fstrcpy(sbase,p2);
+ fstrcpy(sext,p+1);
} else {
- strcpy(sbase,p2);
- strcpy(sext,"");
+ fstrcpy(sbase,p2);
+ fstrcpy(sext,"");
}
}
- matched = do_match(sbase,ebase,case_sig) &&
- (trans2 || do_match(sext,eext,case_sig));
+ matched = unix_do_match(sbase,ebase,case_sig) &&
+ (trans2 || unix_do_match(sext,eext,case_sig));
- DEBUG(5,("mask_match returning %d\n", matched));
+ DEBUG(8,("unix_mask_match returning %d\n", matched));
return matched;
}
+/*********************************************************
+* Recursive routine that is called by mask_match.
+* Does the actual matching. Returns True if matched,
+* False if failed. This is the 'new' NT style matcher.
+*********************************************************/
-
-/****************************************************************************
-become a daemon, discarding the controlling terminal
-****************************************************************************/
-void become_daemon(void)
+BOOL do_match(char *str, char *regexp, int case_sig)
{
-#ifndef NO_FORK_DEBUG
- if (fork())
- exit(0);
+ char *p;
- /* 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);
+ 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++;
+ /* Now eat all characters that match, as
+ we want the *last* character to match. */
+ while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str))))
+ str++;
+ str--; /* We've eaten the match char after the '*' */
+ if(do_match(str,p,case_sig)) {
+ return True;
+ }
+ if(!*str) {
+ return False;
+ } else {
+ str++;
+ }
+ }
+ return False;
+
+ default:
+ if(case_sig) {
+ if(*str != *p) {
+ return False;
+ }
+ } else {
+ if(toupper(*str) != toupper(*p)) {
+ return False;
+ }
}
+ str++, p++;
+ break;
+ }
}
-#endif
-#endif
-#endif
-}
-/****************************************************************************
-calculate the default netmask for an address
-****************************************************************************/
-static void default_netmask(struct in_addr *inm, struct in_addr *iad)
-{
- 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;
+ if(!*p && !*str)
+ return True;
+
+ if (!*p && str[0] == '.' && str[1] == 0) {
+ return(True);
}
- inm->s_addr = htonl(nm);
+
+ if (!*str && *p == '?') {
+ while (*p == '?')
+ p++;
+ return(!*p);
+ }
+
+ if(!*str && (*p == '*' && p[1] == '\0')) {
+ return True;
+ }
+
+ return False;
}
-/****************************************************************************
- 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
+/*********************************************************
+* Routine to match a given string with a regexp - uses
+* simplified regexp that takes * and ? only. Case can be
+* significant or not.
+* The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de>
+* This is the new 'NT style' matcher.
+*********************************************************/
- /* get a default netmask and broadcast */
- default_netmask(if_nmask, if_ipaddr);
+BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
+{
+ char *p;
+ pstring t_pattern, t_filename, te_pattern, te_filename;
+ fstring ebase,eext,sbase,sext;
-#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)
+ BOOL matched = False;
+
+ /* Make local copies of str and regexp */
+ pstrcpy(t_pattern,regexp);
+ pstrcpy(t_filename,str);
+
+#if 0
+ /*
+ * Not sure if this is a good idea. JRA.
+ */
+ if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False))
+ trans2 = False;
#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));
- ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
- ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+#if 0
+ if (!strchr(t_filename,'.')) {
+ pstrcat(t_filename,".");
+ }
+#endif
- if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
- DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
- else {
- ifr = ifc.ifc_req;
+ /* Remove any *? and ** as they are meaningless */
+ string_sub(t_pattern, "*?", "*");
+ string_sub(t_pattern, "**", "*");
- 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;
- }
- }
+ if (strequal(t_pattern,"*"))
+ return(True);
+
+ DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig));
+
+ if(trans2) {
+ /*
+ * Match each component of the regexp, split up by '.'
+ * characters.
+ */
+ char *fp, *rp, *cp2, *cp1;
+ BOOL last_wcard_was_star = False;
+ int num_path_components, num_regexp_components;
+
+ pstrcpy(te_pattern,t_pattern);
+ pstrcpy(te_filename,t_filename);
+ /*
+ * Remove multiple "*." patterns.
+ */
+ string_sub(te_pattern, "*.*.", "*.");
+ num_regexp_components = count_chars(te_pattern, '.');
+ num_path_components = count_chars(te_filename, '.');
+
+ /*
+ * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z
+ */
+ if(num_regexp_components == 0)
+ matched = do_match( te_filename, te_pattern, case_sig);
+ else {
+ for( cp1 = te_pattern, cp2 = te_filename; cp1;) {
+ fp = strchr(cp2, '.');
+ if(fp)
+ *fp = '\0';
+ rp = strchr(cp1, '.');
+ if(rp)
+ *rp = '\0';
+
+ if(cp1[strlen(cp1)-1] == '*')
+ last_wcard_was_star = True;
+ else
+ last_wcard_was_star = False;
+
+ if(!do_match(cp2, cp1, case_sig))
+ break;
+
+ cp1 = rp ? rp + 1 : NULL;
+ cp2 = fp ? fp + 1 : "";
+
+ if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) {
+ /* Eat the extra path components. */
+ int i;
+
+ for(i = 0; i < num_path_components - num_regexp_components; i++) {
+ fp = strchr(cp2, '.');
+ if(fp)
+ *fp = '\0';
+
+ if((cp1 != NULL) && do_match( cp2, cp1, case_sig)) {
+ cp2 = fp ? fp + 1 : "";
+ break;
+ }
+ cp2 = fp ? fp + 1 : "";
+ }
+ num_path_components -= i;
+ }
+ }
+ if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
+ matched = True;
}
- }
-#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;
+
+ /* -------------------------------------------------
+ * Behaviour of Win95
+ * for 8.3 filenames and 8.3 Wildcards
+ * -------------------------------------------------
+ */
+ if (strequal (t_filename, ".")) {
+ /*
+ * Patterns: *.* *. ?. ? are valid
+ *
+ */
+ if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
+ strequal(t_pattern, "?.") || strequal(t_pattern, "?"))
+ matched = True;
+ } else if (strequal (t_filename, "..")) {
+ /*
+ * Patterns: *.* *. ?. ? *.? are valid
+ *
+ */
+ if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
+ strequal(t_pattern, "?.") || strequal(t_pattern, "?") ||
+ strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*"))
+ matched = True;
+ } else {
+
+ if ((p = strrchr (t_pattern, '.'))) {
+ /*
+ * Wildcard has a suffix.
+ */
+ *p = 0;
+ fstrcpy (ebase, t_pattern);
+ if (p[1]) {
+ fstrcpy (eext, p + 1);
+ } else {
+ /* pattern ends in DOT: treat as if there is no DOT */
+ *eext = 0;
+ if (strequal (ebase, "*"))
+ return (True);
+ }
+ } else {
+ /*
+ * No suffix for wildcard.
+ */
+ fstrcpy (ebase, t_pattern);
+ eext[0] = 0;
}
- }
- }
-#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;
+
+ p = strrchr (t_filename, '.');
+ if (p && (p[1] == 0) ) {
+ /*
+ * Filename has an extension of '.' only.
+ */
+ *p = 0; /* nuke dot at end of string */
+ p = 0; /* and treat it as if there is no extension */
}
- 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;
+
+ if (p) {
+ /*
+ * Filename has an extension.
+ */
+ *p = 0;
+ fstrcpy (sbase, t_filename);
+ fstrcpy (sext, p + 1);
+ if (*eext) {
+ matched = do_match(sbase, ebase, case_sig)
+ && do_match(sext, eext, case_sig);
+ } else {
+ /* pattern has no extension */
+ /* Really: match complete filename with pattern ??? means exactly 3 chars */
+ matched = do_match(str, ebase, case_sig);
+ }
+ } else {
+ /*
+ * Filename has no extension.
+ */
+ fstrcpy (sbase, t_filename);
+ fstrcpy (sext, "");
+ if (*eext) {
+ /* pattern has extension */
+ matched = do_match(sbase, ebase, case_sig)
+ && do_match(sext, eext, case_sig);
+ } else {
+ matched = do_match(sbase, ebase, case_sig);
+#ifdef EMULATE_WEIRD_W95_MATCHING
+ /*
+ * Even Microsoft has some problems
+ * Behaviour Win95 -> local disk
+ * is different from Win95 -> smb drive from Nt 4.0
+ * This branch would reflect the Win95 local disk behaviour
+ */
+ if (!matched) {
+ /* a? matches aa and a in w95 */
+ fstrcat (sbase, ".");
+ matched = do_match(sbase, ebase, case_sig);
+ }
#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)));
- }
+ DEBUG(8,("mask_match returning %d\n", matched));
- /* Close up shop */
- (void) close(sock);
-
-#endif
+ return matched;
+}
- /* 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);
- }
- }
+/****************************************************************************
+become a daemon, discarding the controlling terminal
+****************************************************************************/
+void become_daemon(void)
+{
+ if (fork()) {
+ _exit(0);
+ }
- /* 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 */
+ /* detach from the terminal */
+#ifdef HAVE_SETSID
+ setsid();
+#elif defined(TIOCNOTTY)
+ {
+ int i = open("/dev/tty", O_RDWR);
+ if (i != -1) {
+ ioctl(i, (int) TIOCNOTTY, (char *)0);
+ close(i);
+ }
+ }
+#endif /* HAVE_SETSID */
+
+ /* Close fd's 0,1,2. Needed if started by rsh */
+ close_low_fds();
+}
/****************************************************************************
@@ -3402,18 +3066,18 @@ char *fgets_slash(char *s2,int maxlen,FILE *f)
set the length of a file from a filedescriptor.
Returns 0 on success, -1 on failure.
****************************************************************************/
-int set_filelen(int fd, long len)
+int set_filelen(int fd, SMB_OFF_T len)
{
/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
extend a file with ftruncate. Provide alternate implementation
for this */
-#if FTRUNCATE_CAN_EXTEND
- return ftruncate(fd, len);
+#ifdef HAVE_FTRUNCATE_EXTEND
+ return sys_ftruncate(fd, len);
#else
- struct stat st;
+ SMB_STRUCT_STAT st;
char c = 0;
- long currpos = lseek(fd, 0L, SEEK_CUR);
+ SMB_OFF_T currpos = sys_lseek(fd, (SMB_OFF_T)0, SEEK_CUR);
if(currpos < 0)
return -1;
@@ -3421,7 +3085,7 @@ int set_filelen(int fd, long len)
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)
+ if(sys_fstat(fd, &st)<0)
return -1;
#ifdef S_ISFIFO
@@ -3431,38 +3095,24 @@ int set_filelen(int fd, long len)
if(st.st_size == len)
return 0;
if(st.st_size > len)
- return ftruncate(fd, len);
+ return sys_ftruncate(fd, len);
- if(lseek(fd, len-1, SEEK_SET) != len -1)
+ if(sys_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);
+ sys_lseek(fd, currpos, SEEK_SET);
return 0;
#endif
}
-/****************************************************************************
-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);
-}
-
-
-
#ifdef HPUX
/****************************************************************************
this is a version of setbuffer() for those machines that only have setvbuf
****************************************************************************/
-void setbuffer(FILE *f,char *buf,int bufsize)
+ void setbuffer(FILE *f,char *buf,int bufsize)
{
setvbuf(f,buf,_IOFBF,bufsize);
}
@@ -3470,26 +3120,6 @@ void setbuffer(FILE *f,char *buf,int bufsize)
/****************************************************************************
-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 (!p)
- strcpy(buf,path);
- else
- {
- *p = 0;
- strcpy(buf,path);
- *p = '\\';
- }
-
- return(buf);
-}
-
-
-/****************************************************************************
parse out a filename from a path name. Assumes dos style filenames.
****************************************************************************/
static char *filename_dos(char *path,char *buf)
@@ -3497,9 +3127,9 @@ static char *filename_dos(char *path,char *buf)
char *p = strrchr(path,'\\');
if (!p)
- strcpy(buf,path);
+ pstrcpy(buf,path);
else
- strcpy(buf,p+1);
+ pstrcpy(buf,p+1);
return(buf);
}
@@ -3509,9 +3139,16 @@ static char *filename_dos(char *path,char *buf)
/****************************************************************************
expand a pointer to be a particular size
****************************************************************************/
-void *Realloc(void *p,int 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
@@ -3523,138 +3160,11 @@ void *Realloc(void *p,int size)
return(ret);
}
-/****************************************************************************
-set the time on a file
-****************************************************************************/
-BOOL set_filetime(char *fname,time_t mtime)
-{
- struct utimbuf times;
-
- if (null_mtime(mtime)) return(True);
-
- times.modtime = times.actime = mtime;
-
- if (sys_utime(fname,&times)) {
- DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
- }
-
- return(True);
-}
-
-
-#ifdef NOSTRDUP
-/****************************************************************************
-duplicate a string
-****************************************************************************/
-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 )
-{
- DEBUG(0,("Probably got SIGPIPE\nExiting\n"));
- exit(2);
-}
-
-
-#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);
-}
-#endif
-
-
-/****************************************************************************
-return a time at the start of the current month
-****************************************************************************/
-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)
-{
- 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
-
-
/****************************************************************************
get my own name and IP
****************************************************************************/
-BOOL get_myname(char *myname,struct in_addr *ip)
+BOOL get_myname(char *my_name,struct in_addr *ip)
{
struct hostent *hp;
pstring hostname;
@@ -3671,17 +3181,17 @@ BOOL get_myname(char *myname,struct in_addr *ip)
/* get host info */
if ((hp = Get_Hostbyname(hostname)) == 0)
{
- DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname));
+ DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",hostname));
return False;
}
- if (myname)
+ if (my_name)
{
/* split off any parts after an initial . */
char *p = strchr(hostname,'.');
if (p) *p = 0;
- strcpy(myname,hostname);
+ fstrcpy(my_name,hostname);
}
if (ip)
@@ -3696,7 +3206,7 @@ true if two IP addresses are equal
****************************************************************************/
BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
{
- unsigned long a1,a2;
+ uint32 a1,a2;
a1 = ntohl(ip1.s_addr);
a2 = ntohl(ip2.s_addr);
return(a1 == a2);
@@ -3706,7 +3216,7 @@ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
/****************************************************************************
open a socket of the specified type, port and address for incoming data
****************************************************************************/
-int open_socket_in(int type, int port, int dlevel)
+int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
{
struct hostent *hp;
struct sockaddr_in sock;
@@ -3714,28 +3224,25 @@ int open_socket_in(int type, int port, int dlevel)
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));
+ 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 */
+
+#ifdef HAVE_SOCK_SIN_LEN
sock.sin_len = sizeof(sock);
#endif
sock.sin_port = htons( port );
sock.sin_family = hp->h_addrtype;
- sock.sin_addr.s_addr = INADDR_ANY;
+ sock.sin_addr.s_addr = socket_addr;
res = socket(hp->h_addrtype, type, 0);
if (res == -1)
{ DEBUG(0,("socket failed\n")); return -1; }
@@ -3749,16 +3256,16 @@ int open_socket_in(int type, int port, int dlevel)
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)));
+ if (port == SMB_PORT || port == NMB_PORT)
+ DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n",
+ port,inet_ntoa(sock.sin_addr),strerror(errno)));
close(res);
if (dlevel > 0 && port < 1000)
port = 7999;
if (port >= 1000 && port < 9000)
- return(open_socket_in(type,port+1,dlevel));
+ return(open_socket_in(type,port+1,dlevel,socket_addr));
}
return(-1);
@@ -3772,10 +3279,12 @@ int open_socket_in(int type, int port, int dlevel)
/****************************************************************************
create an outgoing socket
**************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port )
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
{
struct sockaddr_in sock_out;
- int res;
+ int res,ret;
+ int connect_loop = 250; /* 250 milliseconds */
+ int loops = (timeout * 1000) / connect_loop;
/* create a socket to write to */
res = socket(PF_INET, type, 0);
@@ -3790,15 +3299,46 @@ int open_socket_out(int type, struct in_addr *addr, int port )
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 */
- if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) {
- DEBUG(0,("connect error: %s\n",strerror(errno)));
- close(res);
- return(-1);
+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(1,("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;
}
@@ -3826,48 +3366,42 @@ int interpret_protocol(char *str,int def)
return(def);
}
-/****************************************************************************
-interpret a security level
-****************************************************************************/
-int interpret_security(char *str,int def)
-{
- 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);
-}
-
/****************************************************************************
interpret an internet address or name into an IP address in 4 byte form
****************************************************************************/
-unsigned long interpret_addr(char *str)
+uint32 interpret_addr(char *str)
{
struct hostent *hp;
- unsigned long res;
+ uint32 res;
+ int i;
+ BOOL pure_address = True;
if (strcmp(str,"0.0.0.0") == 0) return(0);
if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
+ for (i=0; pure_address && str[i]; i++)
+ if (!(isdigit((int)str[i]) || str[i] == '.'))
+ pure_address = False;
+
/* if it's in the form of an IP address then get the lib to interpret it */
- if (isdigit(str[0])) {
+ if (pure_address) {
res = inet_addr(str);
} else {
- /* otherwise assume it's a network name of some sort and use Get_Hostbyname */
+ /* 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;
}
+ if(hp->h_addr == NULL) {
+ DEBUG(3,("Get_Hostbyname: host address is invalid for host %s\n",str));
+ return 0;
+ }
putip((char *)&res,(char *)hp->h_addr);
}
- if (res == (unsigned long)-1) return(0);
+ if (res == (uint32)-1) return(0);
return(res);
}
@@ -3878,8 +3412,8 @@ unsigned long interpret_addr(char *str)
struct in_addr *interpret_addr2(char *str)
{
static struct in_addr ret;
- unsigned long a = interpret_addr(str);
- putip((char *)&ret,(char *)&a);
+ uint32 a = interpret_addr(str);
+ ret.s_addr = a;
return(&ret);
}
@@ -3888,121 +3422,534 @@ struct in_addr *interpret_addr2(char *str)
******************************************************************/
BOOL zero_ip(struct in_addr ip)
{
- unsigned long a;
+ uint32 a;
putip((char *)&a,(char *)&ip);
return(a == 0);
}
-#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)
+/*******************************************************************
+ matchname - determine if host name matches IP address
+ ******************************************************************/
+static BOOL matchname(char *remotehost,struct in_addr addr)
{
- double d;
- time_t ret;
- uint32 tlow,thigh;
- tlow = IVAL(p,0);
- thigh = IVAL(p,4);
+ struct hostent *hp;
+ int i;
+
+ if ((hp = Get_Hostbyname(remotehost)) == 0) {
+ DEBUG(0,("Get_Hostbyname(%s): lookup failure", 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",
+ 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",
+ inet_ntoa(addr), hp->h_name));
+ return False;
+}
- if (thigh == 0) return(0);
+/*******************************************************************
+ 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.
+ ******************************************************************/
+
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
+
+void reset_globals_after_fork(void)
+{
+ global_client_name_done = False;
+ global_client_addr_done = False;
- d = ((double)thigh)*4.0*(double)(1<<30);
- d += (tlow&0xFFF00000);
- d *= 1.0e-7;
+ /*
+ * Re-seed the random crypto generator, so all smbd's
+ * started from the same parent won't generate the same
+ * sequence.
+ */
+ {
+ unsigned char dummy;
+ generate_random_buffer( &dummy, 1, True);
+ }
+}
- /* now adjust by 369 years to make the secs since 1970 */
- d -= TIME_FIXUP_CONSTANT;
+/*******************************************************************
+ return the DNS name of the client
+ ******************************************************************/
+char *client_name(int fd)
+{
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ int length = sizeof(sa);
+ static pstring name_buf;
+ struct hostent *hp;
+ static int last_fd=-1;
+
+ if (global_client_name_done && last_fd == fd)
+ return name_buf;
+
+ last_fd = fd;
+ global_client_name_done = False;
+
+ pstrcpy(name_buf,"UNKNOWN");
+
+ if (fd == -1) {
+ return name_buf;
+ }
+
+ if (getpeername(fd, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed\n"));
+ return name_buf;
+ }
+
+ /* 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",client_addr(fd)));
+ StrnCpy(name_buf,client_addr(fd),sizeof(name_buf) - 1);
+ } else {
+ StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
+ if (!matchname(name_buf, sockin->sin_addr)) {
+ DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr(fd)));
+ pstrcpy(name_buf,"UNKNOWN");
+ }
+ }
+ global_client_name_done = True;
+ return name_buf;
+}
- if (d>=MAXINT)
- return(0);
+/*******************************************************************
+ return the IP addr of the client as a string
+ ******************************************************************/
+char *client_addr(int fd)
+{
+ struct sockaddr sa;
+ struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+ int length = sizeof(sa);
+ static fstring addr_buf;
+ static int last_fd = -1;
- ret = (time_t)(d+0.5);
+ if (global_client_addr_done && fd == last_fd)
+ return addr_buf;
- /* this takes us from kludge-GMT to real GMT */
- ret += TimeDiff(ret) - serverzone;
+ last_fd = fd;
+ global_client_addr_done = False;
- return(ret);
+ fstrcpy(addr_buf,"0.0.0.0");
+
+ if (fd == -1) {
+ return addr_buf;
+ }
+
+ if (getpeername(fd, &sa, &length) < 0) {
+ DEBUG(0,("getpeername failed\n"));
+ return addr_buf;
+ }
+
+ fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+
+ global_client_addr_done = True;
+ return addr_buf;
}
+#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>.
+*******************************************************************/
-/****************************************************************************
-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)
+static void strip_mount_options( pstring *str)
{
- uint32 tlow,thigh;
- double d;
+ if (**str == '-')
+ {
+ char *p = *str;
+ while(*p && !isspace(*p))
+ p++;
+ while(*p && isspace(*p))
+ p++;
+ if(*p) {
+ pstring tmp_str;
- if (t==0) {
- SIVAL(p,0,0); SIVAL(p,4,0);
- return;
+ pstrcpy(tmp_str, p);
+ pstrcpy(*str, tmp_str);
+ }
}
+}
- /* this converts GMT to kludge-GMT */
- t -= TimeDiff(t) - serverzone;
+/*******************************************************************
+ 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.
+*******************************************************************/
- d = (double) (t);
+#ifdef WITH_NISPLUS_HOME
+static char *automount_lookup(char *user_name)
+{
+ static fstring last_key = "";
+ static pstring last_value = "";
+
+ char *nis_map = (char *)lp_nis_home_map_name();
+
+ char nis_domain[NIS_MAXNAMELEN + 1];
+ char buffer[NIS_MAXATTRVAL + 1];
+ nis_result *result;
+ nis_object *object;
+ entry_obj *entry;
+
+ strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN);
+ nis_domain[NIS_MAXNAMELEN] = '\0';
+
+ DEBUG(5, ("NIS+ Domain: %s\n", nis_domain));
+
+ if (strcmp(user_name, last_key))
+ {
+ slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain);
+ DEBUG(5, ("NIS+ querystring: %s\n", buffer));
+
+ if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL))
+ {
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
+ fstrcpy(last_key, ""); pstrcpy(last_value, "");
+ }
+ 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);
+ string_sub(last_value, "&", user_name);
+ fstrcpy(last_key, user_name);
+ }
+ }
+ }
+ nis_freeresult(result);
+ }
+
+ strip_mount_options(&last_value);
- d += TIME_FIXUP_CONSTANT;
+ DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value));
+ return last_value;
+}
+#else /* WITH_NISPLUS_HOME */
+static char *automount_lookup(char *user_name)
+{
+ static fstring last_key = "";
+ static pstring last_value = "";
+
+ 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();
- d *= 1.0e7;
+ if ((nis_error = yp_get_default_domain(&nis_domain)) != 0)
+ {
+ DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
+ return last_value;
+ }
- thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
- tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+ DEBUG(5, ("NIS Domain: %s\n", nis_domain));
- SIVAL(p,0,tlow);
- SIVAL(p,4,thigh);
+ if (!strcmp(user_name, last_key))
+ {
+ nis_result = last_value;
+ nis_result_len = strlen(last_value);
+ nis_error = 0;
+ }
+ else
+ {
+ if ((nis_error = yp_match(nis_domain, nis_map,
+ user_name, strlen(user_name),
+ &nis_result, &nis_result_len)) != 0)
+ {
+ DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n",
+ yperr_string(nis_error), user_name, nis_map));
+ }
+ 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);
+
+ DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
+ return last_value;
}
+#endif /* WITH_NISPLUS_HOME */
+#endif
/*******************************************************************
-sub strings with useful parameters
-********************************************************************/
-void standard_sub_basic(char *s)
+ 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)
{
- if (!strchr(s,'%')) return;
+ static pstring server_name;
- string_sub(s,"%R",remote_proto);
- string_sub(s,"%a",remote_arch);
- string_sub(s,"%m",remote_machine);
- string_sub(s,"%L",local_machine);
+ /* use the local machine name as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+ pstrcpy(server_name, local_machine);
- if (!strchr(s,'%')) return;
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
- string_sub(s,"%v",VERSION);
- string_sub(s,"%h",myhostname);
- string_sub(s,"%U",sesssetup_user);
+ 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
- if (!strchr(s,'%')) return;
+ DEBUG(4,("Home server: %s\n", server_name));
- string_sub(s,"%I",Client_info.addr);
- string_sub(s,"%M",Client_info.name);
- string_sub(s,"%T",timestring());
+ return server_name;
+}
- if (!strchr(s,'%')) return;
+/*******************************************************************
+ 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;
- {
- char pidstr[10];
- sprintf(pidstr,"%d",(int)getpid());
- string_sub(s,"%d",pidstr);
- }
+ /* use the passwd entry as the default */
+ /* this will be the default if WITH_AUTOMOUNT is not used or fails */
+ /* pstrcpy() copes with get_home_dir() returning NULL */
+ pstrcpy(server_path, get_home_dir(user_name));
- if (!strchr(s,'%')) return;
+#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
- {
- struct passwd *pass = Get_Pwnam(sesssetup_user,False);
- if (pass) {
- string_sub(s,"%G",gidtoname(pass->pw_gid));
- }
- }
+ if (lp_nis_home_map())
+ {
+ char *home_path_start;
+ char *automount_value = automount_lookup(user_name);
+ home_path_start = strchr(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);
+ }
+ }
+#endif
+
+ DEBUG(4,("Home server path: %s\n", server_path));
+
+ return server_path;
+}
+
+
+/*******************************************************************
+sub strings with useful parameters
+Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
+Paul Rippin <pr3245@nopc.eurostat.cec.be>
+********************************************************************/
+void standard_sub_basic(char *str)
+{
+ char *s, *p;
+ char pidstr[10];
+ struct passwd *pass;
+ char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user;
+
+ for (s = str ; s && *s && (p = strchr(s,'%')); s = p )
+ {
+ switch (*(p+1))
+ {
+ case 'G' :
+ {
+ if ((pass = Get_Pwnam(username,False))!=NULL)
+ {
+ string_sub(p,"%G",gidtoname(pass->pw_gid));
+ }
+ else
+ {
+ p += 2;
+ }
+ break;
+ }
+ case 'N' : string_sub(p,"%N", automount_server(username)); break;
+ case 'I' : string_sub(p,"%I", client_addr(Client)); break;
+ case 'L' : string_sub(p,"%L", local_machine); break;
+ case 'M' : string_sub(p,"%M", client_name(Client)); break;
+ case 'R' : string_sub(p,"%R", remote_proto); break;
+ case 'T' : string_sub(p,"%T", timestring()); break;
+ case 'U' : string_sub(p,"%U", username); break;
+ case 'a' : string_sub(p,"%a", remote_arch); break;
+ case 'd' :
+ {
+ slprintf(pidstr,sizeof(pidstr) - 1, "%d",(int)getpid());
+ string_sub(p,"%d", pidstr);
+ break;
+ }
+ case 'h' : string_sub(p,"%h", myhostname); break;
+ case 'm' : string_sub(p,"%m", remote_machine); break;
+ case 'v' : string_sub(p,"%v", VERSION); break;
+ case '$' : /* Expand environment variables */
+ {
+ /* Contributed by Branko Cibej <branko.cibej@hermes.si> */
+ fstring envname;
+ char *envval;
+ char *q, *r;
+ int copylen;
+
+ if (*(p+2) != '(')
+ {
+ p+=2;
+ break;
+ }
+ if ((q = strchr(p,')')) == NULL)
+ {
+ DEBUG(0,("standard_sub_basic: Unterminated environment \
+ variable [%s]\n", p));
+ p+=2;
+ break;
+ }
+
+ r = p+3;
+ copylen = MIN((q-r),(sizeof(envname)-1));
+ strncpy(envname,r,copylen);
+ envname[copylen] = '\0';
+
+ if ((envval = getenv(envname)) == NULL)
+ {
+ DEBUG(0,("standard_sub_basic: Environment variable [%s] not set\n",
+ envname));
+ p+=2;
+ break;
+ }
+
+ copylen = MIN((q+1-p),(sizeof(envname)-1));
+ strncpy(envname,p,copylen);
+ envname[copylen] = '\0';
+ string_sub(p,envname,envval);
+ break;
+ }
+ case '\0': p++; break; /* don't run off end if last character is % */
+ default : p+=2; break;
+ }
+ }
+ return;
+}
+
+
+/****************************************************************************
+do some standard substitutions in a string
+****************************************************************************/
+void standard_sub(connection_struct *conn,char *str)
+{
+ char *p, *s, *home;
+
+ for (s=str; (p=strchr(s, '%'));s=p) {
+ switch (*(p+1)) {
+ case 'H':
+ if ((home = get_home_dir(conn->user))) {
+ string_sub(p,"%H",home);
+ } else {
+ p += 2;
+ }
+ break;
+
+ case 'P':
+ string_sub(p,"%P",conn->connectpath);
+ break;
+
+ case 'S':
+ string_sub(p,"%S",
+ lp_servicename(SNUM(conn)));
+ break;
+
+ case 'g':
+ string_sub(p,"%g",
+ gidtoname(conn->gid));
+ break;
+ case 'u':
+ string_sub(p,"%u",conn->user);
+ 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(conn))));
+ break;
+ case '\0':
+ p++;
+ break; /* don't run off the end of the string
+ */
+
+ default: p+=2;
+ break;
+ }
+ }
+
+ standard_sub_basic(str);
+}
+
+
+
+/*******************************************************************
+are two IPs on the same subnet?
+********************************************************************/
+BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
+{
+ uint32 net1,net2,nmask;
+
+ nmask = ntohl(mask.s_addr);
+ net1 = ntohl(ip1.s_addr);
+ net2 = ntohl(ip2.s_addr);
+
+ return((net1 & nmask) == (net2 & nmask));
}
@@ -4022,34 +3969,6 @@ int PutUniCode(char *dst,char *src)
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);
- }
-
- sprintf(syscmd,"%s \"(%s 2>&1) > %s\"",
- smbrun_path,cmd,
- outfile?outfile:"/dev/null");
-
- DEBUG(5,("smbrun - running %s ",syscmd));
- ret = system(syscmd);
- DEBUG(5,("gave %d\n",ret));
- return(ret);
-}
-
-
/****************************************************************************
a wrapper for gethostbyname() that tries with all lower and all upper case
if the initial name fails
@@ -4065,13 +3984,22 @@ struct hostent *Get_Hostbyname(char *name)
exit(0);
}
+
+ /*
+ * This next test is redundent and causes some systems (with
+ * broken isalnum() calls) problems.
+ * JRA.
+ */
+
+#if 0
if (!isalnum(*name2))
{
free(name2);
return(NULL);
}
+#endif /* 0 */
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
@@ -4080,7 +4008,7 @@ struct hostent *Get_Hostbyname(char *name)
/* try with all lowercase */
strlower(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
@@ -4089,7 +4017,7 @@ struct hostent *Get_Hostbyname(char *name)
/* try with all uppercase */
strupper(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
@@ -4107,32 +4035,7 @@ check if a process exists. Does this work on all unixes?
****************************************************************************/
BOOL process_exists(int pid)
{
-#ifdef LINUX
- fstring s;
- sprintf(s,"/proc/%d",pid);
- return(directory_exist(s,NULL));
-#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);
-#endif
+ return(kill(pid,0) == 0 || errno != ESRCH);
}
@@ -4144,7 +4047,7 @@ char *uidtoname(int uid)
static char name[40];
struct passwd *pass = getpwuid(uid);
if (pass) return(pass->pw_name);
- sprintf(name,"%d",uid);
+ slprintf(name, sizeof(name) - 1, "%d",uid);
return(name);
}
@@ -4153,358 +4056,777 @@ turn a gid into a group name
********************************************************************/
char *gidtoname(int gid)
{
- static char name[40];
- struct group *grp = getgrgid(gid);
- if (grp) return(grp->gr_name);
- sprintf(name,"%d",gid);
- return(name);
+ static char name[40];
+ struct group *grp = getgrgid(gid);
+ if (grp) return(grp->gr_name);
+ slprintf(name,sizeof(name) - 1, "%d",gid);
+ return(name);
}
/*******************************************************************
-block sigs
+something really nasty happened - panic!
********************************************************************/
-void BlockSignals(BOOL block)
-{
-#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
+void smb_panic(char *why)
+{
+ char *cmd = lp_panic_action();
+ if (cmd && *cmd) {
+ system(cmd);
+ }
+ DEBUG(0,("PANIC: %s\n", why));
+ exit(1);
}
-#if AJT
+
/*******************************************************************
-my own panic function - not suitable for general use
+a readdir wrapper which just returns the file name
********************************************************************/
-void ajt_panic(void)
+char *readdirname(void *p)
{
- pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &";
- smbrun(cmd,NULL);
-}
+ struct dirent *ptr;
+ char *dname;
+
+ if (!p) return(NULL);
+
+ ptr = (struct dirent *)readdir(p);
+ if (!ptr) return(NULL);
+
+ dname = ptr->d_name;
+
+#ifdef NEXT2
+ if (telldir(p) < 0) return(NULL);
#endif
-#ifdef USE_DIRECT
-#define DIRECT direct
-#else
-#define DIRECT dirent
+#ifdef HAVE_BROKEN_READDIR
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
#endif
+ {
+ static pstring buf;
+ memcpy(buf, dname, NAMLEN(ptr)+1);
+ unix_to_dos(buf, True);
+ dname = buf;
+ }
+
+ return(dname);
+}
+
/*******************************************************************
-a readdir wrapper which just returns the file name
-also return the inode number if requested
+ Utility function used to decide if the last component
+ of a path matches a (possibly wildcarded) entry in a namelist.
********************************************************************/
-char *readdirname(void *p)
-{
- struct DIRECT *ptr;
- char *dname;
- if (!p) return(NULL);
-
- ptr = (struct DIRECT *)readdir(p);
- if (!ptr) return(NULL);
+BOOL is_in_path(char *name, name_compare_entry *namelist)
+{
+ pstring last_component;
+ char *p;
- dname = ptr->d_name;
+ DEBUG(8, ("is_in_path: %s\n", name));
-#ifdef KANJI
+ /* if we have no list it's obviously not in the path */
+ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL)))
{
- static pstring buf;
- strcpy(buf, dname);
- unix_to_dos(buf, True);
- dname = buf;
+ DEBUG(8,("is_in_path: no name list.\n"));
+ return False;
}
-#endif
-#ifdef NEXT2
- if (telldir(p) < 0) return(NULL);
-#endif
+ /* Get the last component of the unix name. */
+ p = strrchr(name, '/');
+ strncpy(last_component, p ? ++p : name, sizeof(last_component)-1);
+ last_component[sizeof(last_component)-1] = '\0';
-#ifdef SUNOS5
- /* this handles a broken compiler setup, causing a mixture
- of BSD and SYSV headers and libraries */
+ for(; namelist->name != NULL; namelist++)
{
- static BOOL broken_readdir = False;
- if (!broken_readdir && !(*(dname)) && strequal("..",dname-2))
+ if(namelist->is_wild)
+ {
+ /*
+ * Look for a wildcard match. Use the old
+ * 'unix style' mask match, rather than the
+ * new NT one.
+ */
+ if (unix_mask_match(last_component, namelist->name, case_sensitive, False))
{
- DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n"));
- broken_readdir = True;
+ DEBUG(8,("is_in_path: mask match succeeded\n"));
+ return True;
}
- if (broken_readdir)
- return(dname-2);
+ }
+ 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;
+ }
+ }
}
-#endif
-
- return(dname);
+ DEBUG(8,("is_in_path: match not found\n"));
+
+ return False;
}
+/*******************************************************************
+ 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 *name_end;
+ char *nameptr = namelist;
+ int num_entries = 0;
+ int i;
+
+ (*ppname_array) = NULL;
+
+ 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(nameptr, '/');
+
+ /* oops - the last check for a / didn't find one. */
+ if (name_end == NULL)
+ break;
+
+ /* next segment please */
+ nameptr = name_end + 1;
+ num_entries++;
+ }
+
+ if(num_entries == 0)
+ return;
+
+ 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(nameptr, '/')) != NULL)
+ {
+ *name_end = 0;
+ }
+
+ /* oops - the last check for a / didn't find one. */
+ if(name_end == NULL)
+ break;
+
+ (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
+ (strchr( nameptr, '*')!=NULL));
+ if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+ {
+ DEBUG(0,("set_namearray: malloc fail (1)\n"));
+ return;
+ }
+ /* next segment please */
+ nameptr = name_end + 1;
+ i++;
+ }
+
+ (*ppname_array)[i].name = NULL;
-#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);
+ return;
}
-#endif
-#ifdef NO_INITGROUPS
-#include <sys/types.h>
-#include <limits.h>
-#include <grp.h>
+/****************************************************************************
+routine to free a namearray.
+****************************************************************************/
-#ifndef NULL
-#define NULL (void *)0
-#endif
+void free_namearray(name_compare_entry *name_array)
+{
+ if(name_array == 0)
+ return;
+
+ if(name_array->name != NULL)
+ free(name_array->name);
+
+ free((char *)name_array);
+}
/****************************************************************************
- some systems don't have an initgroups call
+routine to do file locking
****************************************************************************/
-int initgroups(char *name,gid_t id)
+BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
-#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 HAVE_FCNTL_LOCK
+ SMB_STRUCT_FLOCK lock;
+ int ret;
+
+ if(lp_ole_locking_compat()) {
+ SMB_OFF_T mask = ((SMB_OFF_T)0xC) << (SMB_OFF_T_BITS-4);
+ SMB_OFF_T mask2= ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4);
+
+ /* 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) & mask2);
+ } else {
+ SMB_OFF_T mask = ((SMB_OFF_T)0x8) << (SMB_OFF_T_BITS-4);
+ SMB_OFF_T neg_mask = ~mask;
+
+ /* interpret negative counts as large numbers */
+ if (count < 0)
+ count &= ~mask;
+
+ /* no negative offsets */
+ if(offset < 0)
+ offset &= ~mask;
+
+ /* count + offset must be in range */
+ while ((offset < 0 || (offset + count < 0)) && mask)
{
- 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];
- }
+ offset &= ~mask;
+ mask = ((mask >> 1) & neg_mask);
+ }
+ }
+
+ 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;
+
+ errno = 0;
+
+ ret = fcntl(fd,op,&lock);
+ if (errno == EFBIG)
+ {
+ if( DEBUGLVL( 0 ))
+ {
+ dbgtext("fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n", (double)offset,(double)count);
+ dbgtext("a 'file too large' error. This can happen when using 64 bit lock offsets\n");
+ dbgtext("on 32 bit NFS mounted file systems. Retrying with 32 bit truncated length.\n");
}
- endgrent();
- return(setgroups(i,grouplst));
+ /* 32 bit NFS file system, retry with smaller offset */
+ errno = 0;
+ lock.l_len = count & 0xffffffff;
+ 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 == SMB_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,(int)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 %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)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(8,("Lock call successful\n"));
+
+ return(True);
+#else
+ return(False);
#endif
}
-#endif
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(char *s)
+{
+ int n;
+ BOOL ret = False;
-#if WRAP_MALLOC
+ 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);
+}
-/* undo the wrapping temporarily */
-#undef malloc
-#undef realloc
-#undef free
+/*******************************************************************
+set the horrid remote_arch string based on an enum.
+********************************************************************/
+void set_remote_arch(enum remote_arch_types type)
+{
+ 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_SAMBA:
+ fstrcpy(remote_arch,"Samba");
+ return;
+ default:
+ ra_type = RA_UNKNOWN;
+ fstrcpy(remote_arch, "UNKNOWN");
+ break;
+ }
+}
-/****************************************************************************
-wrapper for malloc() to catch memory errors
-****************************************************************************/
-void *malloc_wrapped(int size,char *file,int line)
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+enum remote_arch_types get_remote_arch(void)
{
-#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);
+ return ra_type;
}
-/****************************************************************************
-wrapper for realloc() to catch memory errors
-****************************************************************************/
-void *realloc_wrapped(void *ptr,int size,char *file,int line)
+
+/*******************************************************************
+skip past some unicode strings in a buffer
+********************************************************************/
+char *skip_unicode_string(char *buf,int n)
{
-#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);
+ while (n--)
+ {
+ while (*buf)
+ buf += 2;
+ buf += 2;
+ }
+ return(buf);
}
-/****************************************************************************
-wrapper for free() to catch memory errors
-****************************************************************************/
-void free_wrapped(void *ptr,char *file,int line)
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistrn2(uint16 *buf, int len)
{
-#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;
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ char *p;
+
+ nexti = (nexti+1)%8;
+
+ DEBUG(10, ("unistrn2: "));
+
+ for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++)
+ {
+ DEBUG(10, ("%4x ", *buf));
+ *p = *buf;
+ }
+
+ DEBUG(10,("\n"));
+
+ *p = 0;
+ return lbuf;
}
-/* 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__)
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr2(uint16 *buf)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ char *p;
-#endif
+ nexti = (nexti+1)%8;
-#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)
+ DEBUG(10, ("unistr2: "));
+
+ for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++)
+ {
+ DEBUG(10, ("%4x ", *buf));
+ *p = *buf;
+ }
+
+ DEBUG(10,("\n"));
+
+ *p = 0;
+ return lbuf;
+}
+
+/*******************************************************************
+create a null-terminated unicode string from a null-terminated ascii string.
+return number of unicode chars copied, excluding the null character.
+
+only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+int struni2(uint16 *p, char *buf)
{
- int len = strlen(p);
+ int len = 0;
- while ( *s != '\0' ) {
- if ( strncmp(s, p, len) == 0 )
- return s;
- s++;
+ if (p == NULL) return 0;
+
+ DEBUG(10, ("struni2: "));
+
+ if (buf != NULL)
+ {
+ for (; *buf && len < MAXUNI-2; len++, p++, buf++)
+ {
+ DEBUG(10, ("%2x ", *buf));
+ *p = *buf;
+ }
+
+ DEBUG(10,("\n"));
}
- return NULL;
+ *p = 0;
+
+ return len;
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer(s) and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr(char *buf)
+{
+ static char lbufs[8][MAXUNI];
+ static int nexti;
+ char *lbuf = lbufs[nexti];
+ char *p;
+
+ nexti = (nexti+1)%8;
+
+ for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf += 2)
+ {
+ *p = *buf;
+ }
+ *p = 0;
+ return lbuf;
}
-#endif /* REPLACE_STRSTR */
-#ifdef REPLACE_MKTIME
/*******************************************************************
-a mktime() replacement for those who don't have it - contributed by
-C.A. Lademann <cal@zls.com>
+strcpy for unicode strings. returns length (in num of wide chars)
********************************************************************/
-#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 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++;
- }
- }
+int unistrcpy(char *dst, char *src)
+{
+ int num_wchars = 0;
- 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
- }
+ while (*src)
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ num_wchars++;
+ }
+ *dst++ = 0;
+ *dst++ = 0;
- return(epoch);
+ return num_wchars;
}
-#endif /* REPLACE_MKTIME */
+/*******************************************************************
+safe string copy into a known length string. maxlength does not
+include the terminating zero.
+********************************************************************/
+char *safe_strcpy(char *dest, char *src, int maxlength)
+{
+ int len;
+
+ if (!dest) {
+ DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
+ return NULL;
+ }
+
+ if (!src) {
+ *dest = 0;
+ return dest;
+ }
+ len = strlen(src);
-#ifdef REPLACE_RENAME
-/* Rename a file. (from libiberty in GNU binutils) */
-int
-rename (zfrom, zto)
- const char *zfrom;
- const char *zto;
+ if (len > maxlength) {
+ DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
+ len-maxlength, src));
+ len = maxlength;
+ }
+
+ memcpy(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, char *src, int maxlength)
{
- if (link (zfrom, zto) < 0)
- {
- if (errno != EEXIST)
- return -1;
- if (unlink (zto) < 0
- || link (zfrom, zto) < 0)
- return -1;
+ int 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",
+ src_len + dest_len - maxlength, src));
+ src_len = maxlength - dest_len;
}
- return unlink (zfrom);
+
+ memcpy(&dest[dest_len], src, src_len);
+ dest[dest_len + src_len] = 0;
+ return dest;
}
-#endif
+/*******************************************************************
+align a pointer to a multiple of 2 bytes
+********************************************************************/
+char *align2(char *q, char *base)
+{
+ if ((q - base) & 1)
+ {
+ q++;
+ }
+ return q;
+}
-#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;
+void print_asc(int level, unsigned char *buf,int len)
{
- 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);
+ int i;
+ for (i=0;i<len;i++)
+ DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
+
+void dump_data(int level,char *buf1,int len)
+{
+ unsigned char *buf = (unsigned char *)buf1;
+ int i=0;
+ if (len<=0) return;
+
+ 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));
}
- endnetgrent();
- return (0);
+ }
+ 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"));
+ }
}
-#endif
+char *tab_depth(int depth)
+{
+ static pstring spaces;
+ memset(spaces, ' ', depth * 4);
+ spaces[depth * 4] = 0;
+ return spaces;
+}
-#if WRAP_MEMCPY
-#undef memcpy
-/*******************************************************************
-a wrapper around memcpy for diagnostic purposes
-********************************************************************/
-void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
+/*****************************************************************
+ Convert a SID to an ascii string.
+*****************************************************************/
+
+char *sid_to_string(pstring sidstr_out, DOM_SID *sid)
{
- 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
+ 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(pstring) - 1, "S-%d-%d", sid->sid_rev_num, ia);
+
+ for (i = 0; i < sid->num_auths; i++)
+ {
+ slprintf(subauth, sizeof(subauth)-1, "-%d", sid->sub_auths[i]);
+ pstrcat(sidstr_out, subauth);
+ }
+
+ DEBUG(7,("sid_to_string returning %s\n", sidstr_out));
+ return sidstr_out;
}
-#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
-#endif
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+*****************************************************************/
+
+BOOL string_to_sid(DOM_SID *sidout, char *sidstr)
+{
+ pstring tok;
+ 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 = atoi(tok);
+
+ 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 = atoi(tok);
+
+ /* 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.
+ */
+ sidout->sub_auths[sidout->num_auths++] = atoi(tok);
+ }
+
+ DEBUG(7,("string_to_sid: converted SID %s ok\n", sidstr));
+
+ return True;
+}
+
+/*****************************************************************************
+ * Provide a checksum on a string
+ *
+ * Input: s - the nul-terminated character string for which the checksum
+ * will be calculated.
+ *
+ * Output: The checksum value calculated for s.
+ *
+ * ****************************************************************************
+ */
+int str_checksum(char *s)
+{
+ 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 */
+
+/*****************************************************************
+zero a memory area then free it. Used to catch bugs faster
+*****************************************************************/
+void zero_free(void *p, size_t size)
+{
+ memset(p, 0, size);
+ free(p);
+}
diff --git a/source/lib/util_hnd.c b/source/lib/util_hnd.c
new file mode 100644
index 00000000000..b1e695360f7
--- /dev/null
+++ b/source/lib/util_hnd.c
@@ -0,0 +1,289 @@
+
+/*
+ * 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,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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 DEBUGLEVEL;
+
+#ifndef MAX_OPEN_POLS
+#define MAX_OPEN_POLS 64
+#endif
+
+struct reg_info
+{
+ /* for use by \PIPE\winreg */
+ fstring name; /* name of registry key */
+};
+
+struct samr_info
+{
+ /* for use by the \PIPE\samr policy */
+ DOM_SID sid;
+ uint32 rid; /* relative id associated with the pol_hnd */
+ uint32 status; /* some sort of flag. best to record it. comes from opnum 0x39 */
+};
+
+static struct policy
+{
+ struct policy *next, *prev;
+ int pnum;
+ BOOL open;
+ POLICY_HND pol_hnd;
+
+ union {
+ struct samr_info samr;
+ struct reg_info reg;
+ } dev;
+} *Policy;
+
+static struct bitmap *bmap;
+
+
+/****************************************************************************
+ create a unique policy handle
+****************************************************************************/
+static void create_pol_hnd(POLICY_HND *hnd)
+{
+ static uint32 pol_hnd_low = 0;
+ static uint32 pol_hnd_high = 0;
+
+ if (hnd == NULL) return;
+
+ /* i severely doubt that pol_hnd_high will ever be non-zero... */
+ pol_hnd_low++;
+ if (pol_hnd_low == 0) pol_hnd_high++;
+
+ SIVAL(hnd->data, 0 , 0x0); /* first bit must be null */
+ SIVAL(hnd->data, 4 , pol_hnd_low ); /* second bit is incrementing */
+ SIVAL(hnd->data, 8 , pol_hnd_high); /* second bit is incrementing */
+ SIVAL(hnd->data, 12, time(NULL)); /* something random */
+ SIVAL(hnd->data, 16, getpid()); /* something more random */
+}
+
+/****************************************************************************
+ initialise policy handle states...
+****************************************************************************/
+void init_lsa_policy_hnd(void)
+{
+ bmap = bitmap_allocate(MAX_OPEN_POLS);
+ if (!bmap) {
+ exit_server("out of memory in init_lsa_policy_hnd\n");
+ }
+}
+
+/****************************************************************************
+ find first available policy slot. creates a policy handle for you.
+****************************************************************************/
+BOOL open_lsa_policy_hnd(POLICY_HND *hnd)
+{
+ int i;
+ struct policy *p;
+
+ i = bitmap_find(bmap, 1);
+
+ if (i == -1) {
+ DEBUG(0,("ERROR: out of Policy Handles!\n"));
+ return False;
+ }
+
+ p = (struct policy *)malloc(sizeof(*p));
+ if (!p) {
+ DEBUG(0,("ERROR: out of memory!\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(p);
+
+ p->open = True;
+ p->pnum = i;
+
+ create_pol_hnd(hnd);
+ memcpy(&p->pol_hnd, hnd, sizeof(*hnd));
+
+ bitmap_set(bmap, i);
+
+ DLIST_ADD(Policy, p);
+
+ DEBUG(4,("Opened policy hnd[%x] ", i));
+ dump_data(4, (char *)hnd->data, sizeof(hnd->data));
+
+ return True;
+}
+
+/****************************************************************************
+ find policy by handle
+****************************************************************************/
+static struct policy *find_lsa_policy(POLICY_HND *hnd)
+{
+ struct policy *p;
+
+ for (p=Policy;p;p=p->next) {
+ if (memcmp(&p->pol_hnd, hnd, sizeof(*hnd)) == 0) {
+ DEBUG(4,("Found policy hnd[%x] ", p->pnum));
+ dump_data(4, (char *)hnd->data, sizeof(hnd->data));
+ return p;
+ }
+ }
+
+ DEBUG(4,("Policy not found: "));
+ dump_data(4, (char *)hnd->data, sizeof(hnd->data));
+
+ return NULL;
+}
+
+/****************************************************************************
+ find policy index by handle
+****************************************************************************/
+int find_lsa_policy_by_hnd(POLICY_HND *hnd)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ return p?p->pnum:-1;
+}
+
+/****************************************************************************
+ set samr rid
+****************************************************************************/
+BOOL set_lsa_policy_samr_rid(POLICY_HND *hnd, uint32 rid)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy device rid=%x pnum=%x\n",
+ rid, p->pnum));
+
+ p->dev.samr.rid = rid;
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy rid=%x\n",rid));
+ return False;
+}
+
+
+/****************************************************************************
+ set samr pol status. absolutely no idea what this is.
+****************************************************************************/
+BOOL set_lsa_policy_samr_pol_status(POLICY_HND *hnd, uint32 pol_status)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy status=%x pnum=%x\n",
+ pol_status, p->pnum));
+
+ p->dev.samr.status = pol_status;
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy status=%x\n",
+ pol_status));
+ return False;
+}
+
+/****************************************************************************
+ set samr sid
+****************************************************************************/
+BOOL set_lsa_policy_samr_sid(POLICY_HND *hnd, DOM_SID *sid)
+{
+ pstring sidstr;
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy sid=%s pnum=%x\n",
+ sid_to_string(sidstr, sid), p->pnum));
+
+ memcpy(&p->dev.samr.sid, sid, sizeof(*sid));
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy sid=%s\n",
+ sid_to_string(sidstr, sid)));
+ return False;
+}
+
+/****************************************************************************
+ set samr rid
+****************************************************************************/
+uint32 get_lsa_policy_samr_rid(POLICY_HND *hnd)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ uint32 rid = p->dev.samr.rid;
+ DEBUG(3,("Getting policy device rid=%x pnum=%x\n",
+ rid, p->pnum));
+
+ return rid;
+ }
+
+ DEBUG(3,("Error getting policy\n"));
+ return 0xffffffff;
+}
+
+/****************************************************************************
+ set reg name
+****************************************************************************/
+BOOL set_lsa_policy_reg_name(POLICY_HND *hnd, fstring name)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy pnum=%x name=%s\n",
+ p->pnum, name));
+
+ fstrcpy(p->dev.reg.name, name);
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy name=%s\n", name));
+ return False;
+}
+
+/****************************************************************************
+ close an lsa policy
+****************************************************************************/
+BOOL close_lsa_policy_hnd(POLICY_HND *hnd)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (!p) {
+ DEBUG(3,("Error closing policy\n"));
+ return False;
+ }
+
+ DEBUG(3,("Closed policy name pnum=%x\n", p->pnum));
+
+ DLIST_REMOVE(Policy, p);
+
+ bitmap_clear(bmap, p->pnum);
+
+ ZERO_STRUCTP(p);
+
+ free(p);
+
+ return True;
+}
+
diff --git a/source/libsmb/.cvsignore b/source/libsmb/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/libsmb/.cvsignore
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
new file mode 100644
index 00000000000..30f7dc5d99e
--- /dev/null
+++ b/source/libsmb/clientgen.c
@@ -0,0 +1,1905 @@
+/*
+ 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"
+#include "trans2.h"
+
+
+extern int DEBUGLEVEL;
+
+/*****************************************************
+ RAP error codes - a small start but will be extended.
+*******************************************************/
+
+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."},
+ {0, NULL}
+};
+
+/****************************************************************************
+ return a description of an SMB error
+****************************************************************************/
+static char *cli_smb_errstr(struct cli_state *cli)
+{
+ return smb_errstr(cli->inbuf);
+}
+
+/******************************************************
+ Return an error message - either an SMB error or a RAP
+ error.
+*******************************************************/
+
+char *cli_errstr(struct cli_state *cli)
+{
+ static fstring error_message;
+ int errclass;
+ int errnum;
+ int i;
+
+ /*
+ * Errors are of three kinds - smb errors,
+ * dealt with by cli_smb_errstr, NT errors,
+ * whose code is in cli.nt_error, and rap
+ * errors, whose error code is in cli.rap_error.
+ */
+
+ cli_error(cli, &errclass, &errnum);
+ if(errclass != 0)
+ return cli_smb_errstr(cli);
+
+ /*
+ * Was it an NT error ?
+ */
+
+ if(cli->nt_error) {
+ char *nt_msg = get_nt_error_msg(cli->nt_error);
+
+ if(nt_msg == NULL)
+ slprintf(error_message, sizeof(fstring) - 1, "NT code %d", cli->nt_error);
+ else
+ fstrcpy(error_message, nt_msg);
+
+ return error_message;
+ }
+
+ /*
+ * Must have been a rap error.
+ */
+
+ slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error);
+
+ for(i = 0; rap_errmap[i].message != NULL; i++) {
+ if (rap_errmap[i].err == cli->rap_error) {
+ fstrcpy( error_message, rap_errmap[i].message);
+ break;
+ }
+ }
+
+ return error_message;
+}
+
+/****************************************************************************
+setup basics in a outgoing packet
+****************************************************************************/
+static void cli_setup_packet(struct cli_state *cli)
+{
+ cli->rap_error = 0;
+ cli->nt_error = 0;
+ SSVAL(cli->outbuf,smb_pid,cli->pid);
+ SSVAL(cli->outbuf,smb_uid,cli->uid);
+ SSVAL(cli->outbuf,smb_mid,cli->mid);
+ if (cli->protocol > PROTOCOL_CORE) {
+ SCVAL(cli->outbuf,smb_flg,0x8);
+ SSVAL(cli->outbuf,smb_flg2,0x1);
+ }
+}
+
+
+/****************************************************************************
+ send a SMB trans or trans2 request
+ ****************************************************************************/
+static BOOL cli_send_trans(struct cli_state *cli, int trans,
+ char *name, int pipe_name_len,
+ 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;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ bzero(cli->outbuf,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);
+
+ outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 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) {
+ memcpy(p,name, pipe_name_len + 1); /* name[] */
+ } else {
+ *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);
+ set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
+ PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
+
+ show_msg(cli->outbuf);
+ send_smb(cli->fd,cli->outbuf);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout) ||
+ CVAL(cli->inbuf,smb_rcls) != 0) {
+ 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,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+ set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
+ PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
+
+ show_msg(cli->outbuf);
+ send_smb(cli->fd,cli->outbuf);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+static 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;
+
+ *data_len = *param_len = 0;
+
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ 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 (CVAL(cli->inbuf,smb_rcls) != 0)
+ return(False);
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ /* allocate it */
+ *data = Realloc(*data,total_data);
+ *param = Realloc(*param,total_param);
+
+ 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 (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ 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 (CVAL(cli->inbuf,smb_rcls) != 0)
+ return(False);
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+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, int pipe_name_len,
+ 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)
+{
+ if(pipe_name_len == 0)
+ pipe_name_len = strlen(pipe_name);
+
+ cli_send_trans(cli, SMBtrans,
+ pipe_name, pipe_name_len,
+ 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,strlen(PIPE_LANMAN), /* Name, length */
+ 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, BUFFER_SIZE);
+ p += 2;
+ SSVAL(p, 0, BUFFER_SIZE);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = SVAL(rparam,0);
+ p = rdata;
+
+ if (cli->rap_error == 0) {
+ DEBUG(4,("NetWkstaUserLogon success\n"));
+ cli->privilages = SVAL(p, 24);
+ fstrcpy(cli->eff_name,p+2);
+ } else {
+ DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+ return (cli->rap_error == 0);
+}
+
+#if UNUSED_CODE
+/****************************************************************************
+call a NetShareEnum - try and browse available connections on a host
+****************************************************************************/
+BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(char *, uint32, char *))
+{
+ 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);
+ SSVAL(p,2,BUFFER_SIZE);
+ p += 4;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ int res = SVAL(rparam,0);
+ int converter=SVAL(rparam,2);
+ int i;
+
+ if (res == 0)
+ {
+ 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):"";
+ fn(sname, type, cmnt);
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return(count>0);
+}
+#endif
+
+/****************************************************************************
+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 3 arguments: the machine name, the server type and
+the comment.
+****************************************************************************/
+BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(char *, uint32, char *))
+{
+ 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,BUFFER_SIZE);
+ p += 4;
+ SIVAL(p,0,stype);
+ p += 4;
+
+ pstrcpy(p, workgroup);
+ p = skip_string(p,1);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ int res = SVAL(rparam,0);
+ int converter=SVAL(rparam,2);
+ int i;
+
+ if (res == 0) {
+ 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):"";
+ if (comment_offset < 0 || comment_offset > rdrcnt) continue;
+
+ stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ fn(sname, stype, cmnt);
+ }
+ }
+ }
+
+ if (rparam) free(rparam);
+ if (rdata) free(rdata);
+
+ return(count > 0);
+}
+
+
+
+
+static 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}
+ };
+
+
+/****************************************************************************
+send a session setup
+****************************************************************************/
+BOOL cli_session_setup(struct cli_state *cli,
+ char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup)
+{
+ char *p;
+ fstring pword;
+
+ if (cli->protocol < PROTOCOL_LANMAN1)
+ return True;
+
+ if (passlen > sizeof(pword)-1) {
+ return False;
+ }
+
+ if(((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
+ /* Null session connect. */
+ pword[0] = '\0';
+ } else {
+ if ((cli->sec_mode & 2) && passlen != 24) {
+ passlen = 24;
+ SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
+ } else {
+ memcpy(pword, pass, passlen);
+ }
+ }
+
+ /* if in share level security then don't send a password now */
+ if (!(cli->sec_mode & 1)) {fstrcpy(pword, "");passlen=1;}
+
+ /* send a session setup command */
+ bzero(cli->outbuf,smb_size);
+
+ if (cli->protocol < PROTOCOL_NT1) {
+ set_message(cli->outbuf,10,1 + strlen(user) + passlen,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;
+ pstrcpy(p,user);
+ strupper(p);
+ } else {
+ 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,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);
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += SVAL(cli->outbuf,smb_vwv7);
+ memcpy(p,ntpass,ntpasslen);
+ p += SVAL(cli->outbuf,smb_vwv8);
+ pstrcpy(p,user);
+ strupper(p);
+ p = skip_string(p,1);
+ pstrcpy(p,workgroup);
+ strupper(p);
+ p = skip_string(p,1);
+ pstrcpy(p,"Unix");p = skip_string(p,1);
+ pstrcpy(p,"Samba");p = skip_string(p,1);
+ set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
+ }
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ /* use the returned uid from now on */
+ cli->uid = SVAL(cli->inbuf,smb_uid);
+
+ return True;
+}
+
+/****************************************************************************
+ Send a uloggoff.
+*****************************************************************************/
+
+BOOL cli_ulogoff(struct cli_state *cli)
+{
+ bzero(cli->outbuf,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 */
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ return CVAL(cli->inbuf,smb_rcls) == 0;
+}
+
+/****************************************************************************
+send a tconX
+****************************************************************************/
+BOOL cli_send_tconX(struct cli_state *cli,
+ char *share, char *dev, char *pass, int passlen)
+{
+ fstring fullshare, pword;
+ char *p;
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ if (cli->sec_mode & 1) {
+ passlen = 1;
+ pass = "";
+ }
+
+ if ((cli->sec_mode & 2) && *pass && passlen != 24) {
+ passlen = 24;
+ SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
+ } else {
+ memcpy(pword, pass, passlen);
+ }
+
+ slprintf(fullshare, sizeof(fullshare)-1,
+ "\\\\%s\\%s", cli->desthost, share);
+
+ set_message(cli->outbuf,4,
+ 2 + strlen(fullshare) + passlen + strlen(dev),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;
+ fstrcpy(p,fullshare);
+ p = skip_string(p,1);
+ pstrcpy(p,dev);
+
+ SCVAL(cli->inbuf,smb_rcls, 1);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ cli->cnum = SVAL(cli->inbuf,smb_tid);
+ return True;
+}
+
+
+/****************************************************************************
+send a tree disconnect
+****************************************************************************/
+BOOL cli_tdis(struct cli_state *cli)
+{
+ bzero(cli->outbuf,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);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ return CVAL(cli->inbuf,smb_rcls) == 0;
+}
+
+#if UNUSED_CODE
+/****************************************************************************
+rename a file
+****************************************************************************/
+BOOL cli_mv(struct cli_state *cli, char *fname_src, char *fname_dst)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), 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);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ pstrcpy(p,fname_src);
+ p = skip_string(p,1);
+ *p++ = 4;
+ pstrcpy(p,fname_dst);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+#endif
+
+/****************************************************************************
+delete a file
+****************************************************************************/
+BOOL cli_unlink(struct cli_state *cli, char *fname)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,1, 2 + strlen(fname),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;
+ pstrcpy(p,fname);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+create a directory
+****************************************************************************/
+BOOL cli_mkdir(struct cli_state *cli, char *dname)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,0, 2 + strlen(dname),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;
+ pstrcpy(p,dname);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+remove a directory
+****************************************************************************/
+BOOL cli_rmdir(struct cli_state *cli, char *dname)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,0, 2 + strlen(dname),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;
+ pstrcpy(p,dname);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+
+
+/****************************************************************************
+open a file
+****************************************************************************/
+int cli_open(struct cli_state *cli, 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_RDWR) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_WRONLY) == O_WRONLY) {
+ accessmode |= 1;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= (1<<14);
+ }
+#endif /* O_SYNC */
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,15,1 + strlen(fname),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);
+
+ p = smb_buf(cli->outbuf);
+ pstrcpy(p,fname);
+ p = skip_string(p,1);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return -1;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2);
+}
+
+
+
+
+/****************************************************************************
+ close a file
+****************************************************************************/
+BOOL cli_close(struct cli_state *cli, int fnum)
+{
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,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);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ lock a file
+****************************************************************************/
+BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,8,10,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, 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);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ unlock a file
+****************************************************************************/
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,8,10,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, timeout);
+ 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);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ read from a file
+****************************************************************************/
+int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,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);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return -1;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return -1;
+ }
+
+ size = SVAL(cli->inbuf, smb_vwv5);
+ p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
+
+ memcpy(buf, p, size);
+
+ return size;
+}
+
+
+/****************************************************************************
+ write to a file
+****************************************************************************/
+int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,12,size,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);
+
+ 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);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return -1;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf, smb_vwv2);
+}
+
+
+/****************************************************************************
+do a SMBgetatr call
+****************************************************************************/
+BOOL cli_getatr(struct cli_state *cli, char *fname,
+ int *attr, uint32 *size, time_t *t)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,0,strlen(fname)+2,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;
+ pstrcpy(p+1, fname);
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ 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, char *fname, int attr, time_t t)
+{
+ char *p;
+
+ bzero(cli->outbuf,smb_size);
+ bzero(cli->inbuf,smb_size);
+
+ set_message(cli->outbuf,8,strlen(fname)+4,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;
+ pstrcpy(p+1, fname);
+ p = skip_string(p,1);
+ *p = 4;
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
+ return False;
+ }
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+send a qpathinfo call
+****************************************************************************/
+BOOL cli_qpathinfo(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = strlen(fname) + 7;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, SMB_INFO_STANDARD);
+ pstrcpy(&param[6], fname);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, 0, /* Name, length */
+ -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 = make_unix_date2(rdata+0);
+ }
+ if (a_time) {
+ *a_time = make_unix_date2(rdata+4);
+ }
+ if (m_time) {
+ *m_time = make_unix_date2(rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+
+ if (rdata) free(rdata);
+ if (rparam) free(rparam);
+ return True;
+}
+
+/****************************************************************************
+send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
+****************************************************************************/
+BOOL cli_qpathinfo2(struct cli_state *cli, char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, uint32 *size)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = strlen(fname) + 7;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
+ pstrcpy(&param[6], fname);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, 0, /* name, length */
+ -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 (size) {
+ *size = IVAL(rdata, 40);
+ }
+
+ if (rdata) free(rdata);
+ if (rparam) free(rparam);
+ return True;
+}
+
+
+/****************************************************************************
+send a qfileinfo call
+****************************************************************************/
+BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
+ time_t *c_time, time_t *a_time, time_t *m_time, uint32 *size)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = 4;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_INFO_STANDARD);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, 0, /* name, length */
+ -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 < 22) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = make_unix_date2(rdata+0);
+ }
+ if (a_time) {
+ *a_time = make_unix_date2(rdata+4);
+ }
+ if (m_time) {
+ *m_time = make_unix_date2(rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+
+ if (rdata) free(rdata);
+ if (rparam) free(rparam);
+ return True;
+}
+
+/****************************************************************************
+Send a SamOEMChangePassword command
+****************************************************************************/
+
+BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
+ 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;
+ int new_pw_len = strlen(new_password);
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+
+ if(strlen(user) >= sizeof(fstring)-1) {
+ DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
+ return False;
+ }
+
+ if(new_pw_len > 512) {
+ DEBUG(0,("cli_oem_change_password: new password for user %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);
+
+ /*
+ * 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, sizeof(data), False);
+ fstrcpy( &data[512 - new_pw_len], new_password);
+ SIVAL(data, 512, new_pw_len);
+
+ /*
+ * Get the Lanman hash of the old password, we
+ * use this as the key to SamOEMHash().
+ */
+ memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
+ fstrcpy(upper_case_old_pw, old_password);
+ strupper(upper_case_old_pw);
+ E_P16((uchar *)upper_case_old_pw, old_pw_hash);
+
+ SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
+
+ /*
+ * Now place the old password hash in the data.
+ */
+ memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
+ fstrcpy(upper_case_new_pw, new_password);
+ strupper(upper_case_new_pw);
+
+ 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,strlen(PIPE_LANMAN), /* name, length */
+ 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);
+ }
+
+ if (rparam)
+ free(rparam);
+ if (rdata)
+ free(rdata);
+
+ return (cli->rap_error == 0);
+}
+
+/****************************************************************************
+send a negprot command
+****************************************************************************/
+BOOL cli_negprot(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+ int plength;
+
+ bzero(cli->outbuf,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;
+ pstrcpy(p,prots[numprots].name);
+ p += strlen(p) + 1;
+ }
+
+ CVAL(cli->outbuf,smb_com) = SMBnegprot;
+ cli_setup_packet(cli);
+
+ CVAL(smb_buf(cli->outbuf),0) = 2;
+
+ send_smb(cli->fd,cli->outbuf);
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (CVAL(cli->inbuf,smb_rcls) != 0 ||
+ ((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_xmit = IVAL(cli->inbuf,smb_vwv3+1);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
+ /* this time arrives in real GMT */
+ cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
+ memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
+ if (IVAL(cli->inbuf,smb_vwv9+1) & 1)
+ cli->readbraw_supported =
+ cli->writebraw_supported = True;
+ } 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)*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);
+ memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
+ } else {
+ /* the old core protocol */
+ cli->sec_mode = 0;
+ cli->serverzone = TimeDiff(time(NULL));
+ }
+
+ 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;
+ /* 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 */
+
+ send_smb(cli->fd,cli->outbuf);
+ DEBUG(5,("Sent session request\n"));
+
+ if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
+ return False;
+
+#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,0);
+ return False;
+ }
+ return(True);
+}
+
+
+/****************************************************************************
+open the client sockets
+****************************************************************************/
+BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
+{
+ struct in_addr dest_ip;
+ extern struct in_addr ipzero;
+
+ fstrcpy(cli->desthost, host);
+
+ if (!ip || ip_equal(*ip, ipzero)) {
+ if(!resolve_name( cli->desthost, &dest_ip)) {
+ return False;
+ }
+ } else {
+ dest_ip = *ip;
+ }
+
+
+ cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
+ if (cli->fd == -1)
+ return False;
+
+ return True;
+}
+
+
+/****************************************************************************
+initialise a client structure
+****************************************************************************/
+BOOL cli_initialise(struct cli_state *cli)
+{
+ if (cli->initialised) cli_shutdown(cli);
+
+ memset(cli, 0, sizeof(*cli));
+ cli->fd = -1;
+ cli->cnum = -1;
+ cli->pid = getpid();
+ cli->mid = 1;
+ cli->uid = getuid();
+ cli->protocol = PROTOCOL_NT1;
+ cli->timeout = 20000;
+ cli->bufsize = 0x10000;
+ cli->max_xmit = cli->bufsize - 4;
+ cli->outbuf = (char *)malloc(cli->bufsize);
+ cli->inbuf = (char *)malloc(cli->bufsize);
+ if (!cli->outbuf || !cli->inbuf) return False;
+ cli->initialised = 1;
+ return True;
+}
+
+/****************************************************************************
+shutdown a client structure
+****************************************************************************/
+void cli_shutdown(struct cli_state *cli)
+{
+ if (cli->outbuf) free(cli->outbuf);
+ if (cli->inbuf) free(cli->inbuf);
+#ifdef WITH_SSL
+ if (cli->fd != -1) sslutil_disconnect(cli->fd);
+#endif /* WITH_SSL */
+ if (cli->fd != -1) close(cli->fd);
+ memset(cli, 0, sizeof(*cli));
+}
+
+/****************************************************************************
+ return error codes for the last packet
+****************************************************************************/
+void cli_error(struct cli_state *cli, int *eclass, int *num)
+{
+ *eclass = CVAL(cli->inbuf,smb_rcls);
+ *num = SVAL(cli->inbuf,smb_err);
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+int cli_setpid(struct cli_state *cli, int pid)
+{
+ int ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, reading in a password.
+****************************************************************************/
+BOOL cli_reestablish_connection(struct cli_state *cli)
+{
+ struct nmb_name calling;
+ struct nmb_name called;
+ fstring dest_host;
+ struct in_addr dest_ip;
+ fstring share;
+ fstring dev;
+ BOOL do_tcon = False;
+
+ if (!cli->initialised || cli->fd == -1)
+ {
+ DEBUG(3,("cli_reestablish_connection: not connected\n"));
+ return False;
+ }
+
+ /* copy the parameters necessary to re-establish the connection */
+
+ if (cli->cnum != 0)
+ {
+ fstrcpy(share, cli->share);
+ fstrcpy(dev , cli->dev);
+ do_tcon = True;
+ }
+
+ memcpy(&called , &(cli->called ), sizeof(called ));
+ memcpy(&calling, &(cli->calling), sizeof(calling));
+ fstrcpy(dest_host, cli->full_dest_host_name);
+ dest_ip = cli->dest_ip;
+
+ DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
+ namestr(&calling), namestr(&called), inet_ntoa(dest_ip),
+ cli->user_name, cli->domain));
+
+ return cli_establish_connection(cli,
+ dest_host, &dest_ip,
+ &calling, &called,
+ share, dev, False, do_tcon);
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, reading in a password.
+****************************************************************************/
+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",
+ namestr(calling), namestr(called), inet_ntoa(*dest_ip),
+ cli->user_name, cli->domain));
+
+ /* establish connection */
+
+ if ((!cli->initialised))
+ {
+ return 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",
+ namestr(calling), 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)
+ {
+ /* attempt clear-text session */
+
+ fstring passwd;
+
+ pwd_get_cleartext(&(cli->pwd), passwd);
+
+ /* attempt clear-text session */
+ if (!cli_session_setup(cli, cli->user_name,
+ passwd, strlen(passwd),
+ 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 */
+ uchar nt_sess_pwd[24];
+ uchar 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->cryptkey);
+ 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;
+ }
+
+ 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;
+}
diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c
new file mode 100644
index 00000000000..26d5c13bc9a
--- /dev/null
+++ b/source/libsmb/credentials.c
@@ -0,0 +1,222 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+
+
+/****************************************************************************
+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/namequery.c b/source/libsmb/namequery.c
new file mode 100644
index 00000000000..f988504bba5
--- /dev/null
+++ b/source/libsmb/namequery.c
@@ -0,0 +1,575 @@
+/*
+ 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"
+
+extern pstring scope;
+extern int DEBUGLEVEL;
+
+/* nmbd.c sets this to True. */
+BOOL global_in_nmbd = False;
+
+/****************************************************************************
+interpret a node status response
+****************************************************************************/
+static void _interpret_node_status(char *p, char *master,char *rname)
+{
+ int numnames = CVAL(p,0);
+ DEBUG(1,("received %d names\n",numnames));
+
+ if (rname) *rname = 0;
+ if (master) *master = 0;
+
+ p += 1;
+ while (numnames--)
+ {
+ char qname[17];
+ int type;
+ fstring flags;
+ int i;
+ *flags = 0;
+ StrnCpy(qname,p,15);
+ type = CVAL(p,15);
+ p += 16;
+
+ fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
+ if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
+ if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
+ if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
+ if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
+ if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
+ if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
+ if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
+ if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
+
+ if (master && !*master && type == 0x1d) {
+ StrnCpy(master,qname,15);
+ trim_string(master,NULL," ");
+ }
+
+ if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
+ StrnCpy(rname,qname,15);
+ trim_string(rname,NULL," ");
+ }
+
+ for (i = strlen( qname) ; --i >= 0 ; ) {
+ if (!isprint((int)qname[i])) qname[i] = '.';
+ }
+ DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
+ p+=2;
+ }
+ DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
+ IVAL(p,20),IVAL(p,24)));
+}
+
+
+/****************************************************************************
+ 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)(struct packet_struct *))
+{
+ 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;
+ static int name_trn_id = 0;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
+ ((unsigned)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 = 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;
+
+ 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);
+
+ retries--;
+
+ 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--;
+ }
+
+ if ((p2=receive_packet(fd,NMB_PACKET,90)))
+ {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ 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);
+ }
+ }
+
+
+ DEBUG(0,("No status response (this is not unusual)\n"));
+
+ return(False);
+}
+
+
+/****************************************************************************
+ 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,char *name,int name_type, BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
+{
+ 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;
+ static int name_trn_id = 0;
+ struct in_addr *ip_list = NULL;
+
+ bzero((char *)&p,sizeof(p));
+ (*count) = 0;
+
+ if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
+ ((unsigned)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 = 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,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 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_packet(fd,NMB_PACKET,90)))
+ {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ 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;
+ }
+
+ ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
+ ((*count)+nmb2->answers->rdlength/6));
+ if (ip_list) {
+ DEBUG(fn?3: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]);
+ DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
+ (*count)++;
+ }
+ DEBUG(fn?3:2,(")\n"));
+ }
+ found=True; retries=0;
+ free_packet(p2);
+ if (fn) break;
+ }
+ }
+
+ return ip_list;
+}
+
+/********************************************************
+ Start parsing the lmhosts file.
+*********************************************************/
+
+FILE *startlmhosts(char *fname)
+{
+ FILE *fp = fopen(fname,"r");
+ 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( FILE *fp, char *name, int *name_type, struct in_addr *ipaddr)
+{
+ pstring line;
+
+ while(!feof(fp) && !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(name)))
+ ++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(flags,'G') || strchr(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(name, '#')) != NULL)
+ {
+ char *endptr;
+
+ ptr++;
+ *name_type = (int)strtol(ptr, &endptr,0);
+
+ 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(FILE *fp)
+{
+ fclose(fp);
+}
+
+/********************************************************
+ 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.
+*********************************************************/
+
+BOOL resolve_name(char *name, struct in_addr *return_ip)
+{
+ int i;
+ BOOL pure_address = True;
+ pstring name_resolve_list;
+ fstring tok;
+ char *ptr;
+
+ if (strcmp(name,"0.0.0.0") == 0) {
+ return_ip->s_addr = 0;
+ return True;
+ }
+ if (strcmp(name,"255.255.255.255") == 0) {
+ return_ip->s_addr = 0xFFFFFFFF;
+ return True;
+ }
+
+ for (i=0; pure_address && name[i]; i++)
+ if (!(isdigit((int)name[i]) || name[i] == '.'))
+ pure_address = False;
+
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (pure_address) {
+ return_ip->s_addr = inet_addr(name);
+ 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")) {
+
+ /*
+ * "host" means do a localhost, or dns lookup.
+ */
+
+ struct hostent *hp;
+
+ DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
+
+ if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
+ putip((char *)return_ip,(char *)hp->h_addr);
+ return True;
+ }
+
+ } else if(strequal( tok, "lmhosts")) {
+
+ /*
+ * "lmhosts" means parse the local lmhosts file.
+ */
+
+ FILE *fp;
+ pstring lmhost_name;
+ int name_type;
+
+ DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
+
+ fp = startlmhosts( LMHOSTSFILE );
+ if(fp) {
+ while( getlmhostsent(fp, lmhost_name, &name_type, return_ip ) ) {
+ if( strequal(name, lmhost_name )) {
+ endlmhosts(fp);
+ return True;
+ }
+ }
+ endlmhosts(fp);
+ }
+
+ } else if(strequal( tok, "wins")) {
+
+ int sock;
+
+ /*
+ * "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_name: Attempting wins lookup for name %s<0x20>\n", name));
+
+ if(*lp_wins_server()) {
+ struct in_addr wins_ip = *interpret_addr2(lp_wins_server());
+ BOOL wins_ismyip = ismyip(wins_ip);
+
+ if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()) );
+
+ if (sock != -1) {
+ struct in_addr *iplist = NULL;
+ int count;
+ iplist = name_query(sock, name, 0x20, False, True, wins_ip, &count, NULL);
+ if(iplist != NULL) {
+ *return_ip = iplist[0];
+ free((char *)iplist);
+ close(sock);
+ return True;
+ }
+ close(sock);
+ }
+ }
+ } else {
+ DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
+ }
+ } else if(strequal( tok, "bcast")) {
+
+ int sock;
+
+ /*
+ * "bcast" means do a broadcast lookup on all the local interfaces.
+ */
+
+ DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
+
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()) );
+
+ if (sock != -1) {
+ struct in_addr *iplist = NULL;
+ int count;
+ int num_interfaces = iface_count();
+ set_socket_options(sock,"SO_BROADCAST");
+ /*
+ * Lookup the name on all the interfaces, return on
+ * the first successful match.
+ */
+ for( i = 0; i < num_interfaces; 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));
+ iplist = name_query(sock, name, 0x20, True, False, sendto_ip, &count, NULL);
+ if(iplist != NULL) {
+ *return_ip = iplist[0];
+ free((char *)iplist);
+ close(sock);
+ return True;
+ }
+ }
+ close(sock);
+ }
+
+ } else {
+ DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
+ }
+ }
+
+ return False;
+}
diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c
index 67432271737..d08003133f1 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,15 +21,134 @@
*/
#include "includes.h"
-#include "nameserv.h"
extern int DEBUGLEVEL;
-int num_good_sends=0;
-int num_good_receives=0;
-static uint16 name_trn_id = 0;
-BOOL CanRecurse = True;
-extern pstring scope;
+int num_good_sends = 0;
+int num_good_receives = 0;
+
+static 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 }
+};
+
+/****************************************************************************
+ * Lookup a nmb opcode name.
+ ****************************************************************************/
+static char *lookup_opcode_name( int opcode )
+{
+ 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,
+ 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++)
+ {
+ unsigned char 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", (unsigned char)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",
+ 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
@@ -38,7 +157,7 @@ static BOOL handle_name_ptrs(unsigned char *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,8 +173,7 @@ 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 offset,int length, struct nmb_name *name)
{
int m,n=0;
unsigned char *ubuf = (unsigned char *)inbuf;
@@ -81,7 +199,7 @@ static int parse_nmb_name(char *inbuf,int offset,int length,
unsigned char 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,7 +208,7 @@ 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 = ((unsigned char)name->name[15]) & 0xff;
/* remove trailing spaces */
name->name[15] = 0;
@@ -134,8 +252,9 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
/* special case for wildcard name */
bzero(buf1,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,7 +272,7 @@ 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,'.'))) {
@@ -177,20 +296,19 @@ char *namestr(struct nmb_name *n)
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);
@@ -246,6 +364,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(unsigned char *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
@@ -304,6 +443,9 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
/* 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 +453,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,9 +493,119 @@ 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:
+
+ if(copy_nmb->answers)
+ free((char *)copy_nmb->answers);
+ if(copy_nmb->nsrecs)
+ free((char *)copy_nmb->nsrecs);
+ if(copy_nmb->additional)
+ free((char *)copy_nmb->additional);
+ free((char *)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);
@@ -361,12 +613,24 @@ void free_nmb_packet(struct nmb_packet *nmb)
}
/*******************************************************************
+ 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. */
+}
+
+/*******************************************************************
free up any resources associated with a packet
******************************************************************/
void free_packet(struct packet_struct *packet)
{
+ if (packet->locked)
+ return;
if (packet->packet_type == NMB_PACKET)
free_nmb_packet(&packet->packet.nmb);
+ else if (packet->packet_type == DGRAM_PACKET)
+ free_dgram_packet(&packet->packet.dgram);
free(packet);
}
@@ -382,7 +646,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
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);
@@ -394,6 +658,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
packet->ip = lastip;
packet->port = lastport;
packet->fd = fd;
+ packet->locked = False;
packet->timestamp = time(NULL);
packet->packet_type = packet_type;
switch (packet_type)
@@ -407,14 +672,16 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
break;
}
if (!ok) {
+ DEBUG(10,("parse_nmb: discarding packet id = %d\n",
+ packet->packet.nmb.header.name_trn_id));
free(packet);
return(NULL);
}
num_good_receives++;
- DEBUG(4,("%s received a packet of len %d from (%s) port %d\n",
- timestring(),length,inet_ntoa(packet->ip),packet->port));
+ DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
+ length, inet_ntoa(packet->ip), packet->port ) );
return(packet);
}
@@ -434,8 +701,8 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
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 ) );
ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
sizeof(sock_out)) >= 0);
@@ -494,15 +761,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, char *name, int type, char *this_scope )
{
- strcpy(n->name,name);
- strupper(n->name);
- n->name_type = type;
- strcpy(n->scope,this_scope);
+ memset( (char *)n, '\0', sizeof(struct nmb_name) );
+ StrnCpy( n->name, name, 15 );
+ strupper( n->name );
+ n->name_type = (unsigned int)type & 0xFF;
+ StrnCpy( n->scope, this_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
@@ -522,12 +801,15 @@ static int build_nmb(char *buf,struct packet_struct *p)
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,10 +832,27 @@ 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);
}
@@ -572,6 +871,7 @@ BOOL send_packet(struct packet_struct *p)
{
case NMB_PACKET:
len = build_nmb(buf,p);
+ debug_nmb_packet(p);
break;
case DGRAM_PACKET:
@@ -598,7 +898,7 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
timeout.tv_sec = t/1000;
timeout.tv_usec = 1000*(t%1000);
- sys_select(&fds,&timeout);
+ sys_select(fd+1,&fds,&timeout);
if (FD_ISSET(fd,&fds))
return(read_packet(fd,type));
@@ -608,329 +908,46 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
/****************************************************************************
-interpret a node status response
-****************************************************************************/
-static void interpret_node_status(char *p, char *master,char *rname)
-{
- int level = (master||rname)?4:0;
- int numnames = CVAL(p,0);
- DEBUG(level,("received %d names\n",numnames));
-
- if (rname) *rname = 0;
- if (master) *master = 0;
-
- 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 (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)));
-}
-
-
-/****************************************************************************
- 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)())
+return the number of bits that match between two 4 character buffers
+ ***************************************************************************/
+static int matching_bits(uchar *p1, uchar *p2)
{
- 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);
-
- retries--;
-
- 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--;
- }
-
- 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);
+ int i, j, ret = 0;
+ for (i=0; i<4; i++) {
+ if (p1[i] != p2[i]) break;
+ ret += 8;
}
- }
-
- DEBUG(0,("No status response (this is not unusual)\n"));
+ if (i==4) return ret;
- return(False);
+ 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];
+
/****************************************************************************
- 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)())
+compare two query reply records
+ ***************************************************************************/
+static int name_query_comp(uchar *p1, uchar *p2)
{
- 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);
-
- retries--;
-
- 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--;
- }
-
- 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;
- }
- }
-
- return(found);
+ return matching_bits(p2+2, sort_ip) - matching_bits(p1+2, sort_ip);
}
-
/****************************************************************************
- 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)
+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)
{
- 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);
-
- ptr = &dgram->data[0];
-
- /* 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);
-
- 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);
-
- memcpy(p2,buf,len);
- p2 += len;
-
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
-
- p.ip = dest_ip;
- p.port = DGRAM_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
-
- return(send_packet(&p));
-}
+ if (n <= 1) return;
+ putip(sort_ip, (char *)&ip);
+ qsort(data, n, 6, QSORT_CAST name_query_comp);
+}
diff --git a/source/libsmb/nterr.c b/source/libsmb/nterr.c
new file mode 100644
index 00000000000..d2f9335000d
--- /dev/null
+++ b/source/libsmb/nterr.c
@@ -0,0 +1,543 @@
+/* NT error codes. please read nterr.h */
+
+#include "includes.h"
+#include "nterr.h"
+
+typedef struct
+{
+ char *nt_errstr;
+ uint32 nt_errcode;
+
+} nt_err_code_struct;
+
+nt_err_code_struct nt_errs[] =
+{
+ { "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 },
+ { NULL, 0 }
+};
+
+/*****************************************************************************
+ returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+char *get_nt_error_msg(uint32 nt_code)
+{
+ static pstring msg;
+ int idx = 0;
+
+ pstrcpy(msg, "Unknown NT error");
+
+ nt_code &= 0xFFFF;
+
+ while (nt_errs[idx].nt_errstr != NULL)
+ {
+ if (nt_errs[idx].nt_errcode == nt_code)
+ {
+ pstrcpy(msg, nt_errs[idx].nt_errstr);
+ return msg;
+ }
+ idx++;
+ }
+ return msg;
+}
+
diff --git a/source/libsmb/pwd_cache.c b/source/libsmb/pwd_cache.c
new file mode 100644
index 00000000000..92eee015b39
--- /dev/null
+++ b/source/libsmb/pwd_cache.c
@@ -0,0 +1,235 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+initialises a password structure
+****************************************************************************/
+void pwd_init(struct pwd_info *pwd)
+{
+ bzero(pwd->password , sizeof(pwd->password ));
+ bzero(pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd));
+ bzero(pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd));
+ bzero(pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf));
+ bzero(pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf));
+
+ pwd->null_pwd = True; /* safest option... */
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+de-obfuscates a password
+****************************************************************************/
+static void pwd_deobfuscate(struct pwd_info *pwd)
+{
+}
+
+/****************************************************************************
+obfuscates a password
+****************************************************************************/
+static void pwd_obfuscate(struct pwd_info *pwd)
+{
+}
+
+/****************************************************************************
+sets the obfuscation key info
+****************************************************************************/
+void pwd_obfuscate_key(struct pwd_info *pwd, uint32 int_key, char *str_key)
+{
+}
+
+/****************************************************************************
+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);
+
+ if (user_pass == NULL || user_pass[0] == 0)
+ {
+ pwd_set_nullpwd(pwd);
+ }
+ else 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);
+ fstrcpy(pwd->password, clr);
+ pwd->cleartext = True;
+ pwd->null_pwd = False;
+ pwd->crypted = False;
+
+ pwd_obfuscate(pwd);
+}
+
+/****************************************************************************
+ gets a cleartext password
+ ****************************************************************************/
+void pwd_get_cleartext(struct pwd_info *pwd, char *clr)
+{
+ pwd_deobfuscate(pwd);
+ if (pwd->cleartext)
+ {
+ fstrcpy(clr, pwd->password);
+ }
+ else
+ {
+ clr[0] = 0;
+ }
+ pwd_obfuscate(pwd);
+}
+
+/****************************************************************************
+ 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
+ {
+ bzero(pwd->smb_lm_pwd, 16);
+ }
+
+ if (nt_pwd)
+ {
+ memcpy(pwd->smb_nt_pwd, nt_pwd, 16);
+ }
+ else
+ {
+ bzero(pwd->smb_nt_pwd, 16);
+ }
+
+ pwd->null_pwd = False;
+ pwd->cleartext = False;
+ pwd->crypted = False;
+
+ pwd_obfuscate(pwd);
+}
+
+/****************************************************************************
+ gets lm and nt hashed passwords
+ ****************************************************************************/
+void pwd_get_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16])
+{
+ pwd_deobfuscate(pwd);
+ memcpy(lm_pwd, pwd->smb_lm_pwd, 16);
+ memcpy(nt_pwd, pwd->smb_nt_pwd, 16);
+ pwd_obfuscate(pwd);
+}
+
+/****************************************************************************
+ makes lm and nt hashed passwords
+ ****************************************************************************/
+void pwd_make_lm_nt_16(struct pwd_info *pwd, char *clr)
+{
+ pwd_init(pwd);
+
+ nt_lm_owf_gen(clr, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+ pwd->null_pwd = False;
+ pwd->cleartext = False;
+ pwd->crypted = False;
+
+ pwd_obfuscate(pwd);
+}
+
+/****************************************************************************
+ makes lm and nt OWF crypts
+ ****************************************************************************/
+void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8])
+{
+ pwd_deobfuscate(pwd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("client cryptkey: "));
+ dump_data(100, cryptkey, 8);
+#endif
+
+ SMBOWFencrypt(pwd->smb_nt_pwd, cryptkey, pwd->smb_nt_owf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_owf_passwd: "));
+ dump_data(100, pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf));
+ DEBUG(100,("nt_sess_pwd: "));
+ dump_data(100, 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, pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf));
+ DEBUG(100,("lm_sess_pwd: "));
+ dump_data(100, pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd));
+#endif
+
+ pwd->crypted = True;
+
+ pwd_obfuscate(pwd);
+}
+
+/****************************************************************************
+ gets lm and nt crypts
+ ****************************************************************************/
+void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24])
+{
+ pwd_deobfuscate(pwd);
+ memcpy(lm_owf, pwd->smb_lm_owf, 24);
+ memcpy(nt_owf, pwd->smb_nt_owf, 24);
+ pwd_obfuscate(pwd);
+}
diff --git a/source/libsmb/smbdes.c b/source/libsmb/smbdes.c
new file mode 100644
index 00000000000..eebe0dc54fe
--- /dev/null
+++ b/source/libsmb/smbdes.c
@@ -0,0 +1,399 @@
+/*
+ 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.
+*/
+
+
+/* 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(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, unsigned char *in, 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(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(unsigned char *p21, 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(unsigned char *p14, 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, 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,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,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, 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 ? 516 : 16); 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];
+ }
+}
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index a0683b5d282..5a946e22c9d 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -1,9 +1,8 @@
-#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.
This program is free software; you can redistribute it and/or modify
@@ -22,90 +21,11 @@
*/
#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)
-{
- 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);
-}
-
-void D1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
-
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_DECRYPT);
-}
-
-void E1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
-
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_ENCRYPT);
-}
-
-void E_P16(uchar *p14,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);
-}
-
-void E_P24(uchar *p21, uchar *c8, uchar *p24)
-{
- E1(p21, c8, p24);
- E1(p21+7, c8, p24+8);
- E1(p21+14, c8, p24+16);
-}
-
-
/*
This implements the X/Open SMB password encryption
It takes a password, a 8 byte "crypt key" and puts 24 bytes of
@@ -161,30 +81,57 @@ static int _my_mbstowcs(int16 *dst, uchar *src, int len)
void E_md4hash(uchar *passwd, uchar *p16)
{
- int i, len;
+ int len;
int16 wpwd[129];
- MDstruct MD;
-
+
/* Password cannot be longer than 128 characters */
- len = strlen(passwd);
+ len = strlen((char *)passwd);
if(len > 128)
len = 128;
/* Password must be converted to NT unicode */
- _my_mbstowcs( wpwd, passwd, len);
+ _my_mbstowcs(wpwd, passwd, len);
wpwd[len] = 0; /* Ensure string is null terminated */
/* Calculate length in bytes */
len = _my_wcslen(wpwd) * sizeof(int16);
+
+ mdfour(p16, (unsigned char *)wpwd, len);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16])
+{
+ char passwd[130];
+ StrnCpy(passwd, pwd, sizeof(passwd)-1);
+
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash((uchar *)passwd, nt_p16);
+
+ /* Mangle the passwords into Lanman format */
+ passwd[14] = '\0';
+ strupper(passwd);
+
+ /* Calculate the SMB (lanman) hash functions of the password */
+
+ memset(p16, '\0', 16);
+ E_P16((uchar *) passwd, (uchar *)p16);
+
+ /* clear out local copy of user's password (just being paranoid). */
+ bzero(passwd, sizeof(passwd));
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24])
+{
+ 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, 16);
+ E_P24(p21, c8, p24);
}
+
/* Does the NT MD4 hash then des encryption. */
void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
@@ -197,6 +144,4 @@ void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
E_P24(p21, c8, p24);
}
-#else
-void smbencrypt_dummy(void){}
-#endif
+
diff --git a/source/libsmb/smberr.c b/source/libsmb/smberr.c
new file mode 100644
index 00000000000..c2d8884d738
--- /dev/null
+++ b/source/libsmb/smberr.c
@@ -0,0 +1,181 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+
+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."},
+ {"ERRunsup", 50, "The operation is unsupported"},
+ {"ERRnosuchshare", 67, "You specified an invalid share name"},
+ {"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,"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}};
+
+
+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 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)
+ 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);
+}
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 6ff3ab5d125..f088720e0a0 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Locking functions
- 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
@@ -17,43 +17,90 @@
You should have received a copy of the 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.
+
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
-pstring share_del_pending="";
+static struct share_ops *share_ops;
+/****************************************************************************
+ Utility function to map a lock type correctly depending on the real open
+ mode of a file.
+****************************************************************************/
+
+static int map_lock_type( files_struct *fsp, int lock_type)
+{
+ if((lock_type == F_WRLCK) && (fsp->fd_ptr->real_open_flags == O_RDONLY)) {
+ /*
+ * 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_lock_type: Downgrading write lock to read due to read-only file.\n"));
+ return F_RDLCK;
+ } else if( (lock_type == F_RDLCK) && (fsp->fd_ptr->real_open_flags == O_WRONLY)) {
+ /*
+ * Ditto for read locks on write only files.
+ */
+ DEBUG(10,("map_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;
+}
/****************************************************************************
- utility function called to see if a file region is locked
+ Utility function called to see if a file region is locked.
****************************************************************************/
-BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
+BOOL is_locked(files_struct *fsp,connection_struct *conn,
+ SMB_OFF_T count,SMB_OFF_T offset, int lock_type)
{
- int snum = SNUM(cnum);
+ int snum = SNUM(conn);
- if (count == 0)
- return(False);
+ if (count == 0)
+ return(False);
- if (!lp_locking(snum) || !lp_strict_locking(snum))
- return(False);
+ if (!lp_locking(snum) || !lp_strict_locking(snum))
+ return(False);
- return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
- (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
+ /*
+ * 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(fcntl_lock(fsp->fd_ptr->fd,SMB_F_GETLK,offset,count,lock_type));
}
/****************************************************************************
- utility function called by locking requests
+ Utility function called by locking requests.
****************************************************************************/
-BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+BOOL do_lock(files_struct *fsp,connection_struct *conn,
+ SMB_OFF_T count,SMB_OFF_T offset,int lock_type,
+ int *eclass,uint32 *ecode)
{
BOOL ok = False;
- if (!lp_locking(SNUM(cnum)))
+ if (!lp_locking(SNUM(conn)))
return(True);
if (count == 0) {
@@ -62,9 +109,12 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
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));
+ DEBUG(10,("do_lock: lock type %d start=%.0f len=%.0f requested for file %s\n",
+ lock_type, (double)offset, (double)count, fsp->fsp_name ));
+
+ if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
+ ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,
+ map_lock_type(fsp,lock_type));
if (!ok) {
*eclass = ERRDOS;
@@ -76,17 +126,21 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
/****************************************************************************
- utility function called by unlocking requests
+ Utility function called by unlocking requests.
****************************************************************************/
-BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+BOOL do_unlock(files_struct *fsp,connection_struct *conn,
+ SMB_OFF_T count,SMB_OFF_T offset,int *eclass,uint32 *ecode)
{
BOOL ok = False;
- if (!lp_locking(SNUM(cnum)))
+ if (!lp_locking(SNUM(conn)))
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);
+ DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name ));
+
+ if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
+ ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,F_UNLCK);
if (!ok) {
*eclass = ERRDOS;
@@ -96,235 +150,108 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
return True; /* Did unlock */
}
-/*******************************************************************
- name a share file
- ******************************************************************/
-static BOOL share_name(int cnum,struct stat *st,char *name)
+/****************************************************************************
+ Initialise the locking functions.
+****************************************************************************/
+
+BOOL locking_init(int read_only)
{
- 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);
+ if (share_ops)
+ return True;
+
+#ifdef FAST_SHARE_MODES
+ share_ops = locking_shm_init(read_only);
+#else
+ share_ops = locking_slow_init(read_only);
+#endif
+
+ if (!share_ops) {
+ DEBUG(0,("ERROR: Failed to initialise share modes!\n"));
+ return False;
+ }
+
+ return True;
}
/*******************************************************************
- use the fnum to get the share file name
- ******************************************************************/
-static BOOL share_name_fnum(int fnum,char *name)
+ Deinitialize the share_mode management.
+******************************************************************/
+
+BOOL locking_end(void)
{
- struct stat st;
- if (fstat(Files[fnum].fd,&st) != 0) return(False);
- return(share_name(Files[fnum].cnum,&st,name));
+ if (share_ops)
+ return share_ops->stop_mgmt();
+ return True;
}
/*******************************************************************
- 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, int *ptok)
{
- struct stat sbuf;
- if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
+ return share_ops->lock_entry(conn, dev, inode, ptok);
}
/*******************************************************************
- 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.
+******************************************************************/
+BOOL unlock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int token)
{
- struct stat sbuf;
- if (stat(fname,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
-}
-
+ return share_ops->unlock_entry(conn, dev, inode, token);
+}
/*******************************************************************
-get the share mode of a file
+ Get all share mode entries for a dev/inode pair.
********************************************************************/
-int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+int get_share_modes(connection_struct *conn,
+ int token, SMB_DEV_T dev, SMB_INO_T inode,
+ share_mode_entry **shares)
{
- 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);
+ return share_ops->get_entries(conn, token, dev, inode, shares);
}
-
/*******************************************************************
-del the share mode of a file, if we set it last
+ Del the share mode of a file.
********************************************************************/
-void del_share_mode(int fnum)
+void del_share_mode(int token, files_struct *fsp)
{
- 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);
- }
- }
+ share_ops->del_entry(token, fsp);
}
-
/*******************************************************************
-set the share mode of a file
+ Set the share mode of a file. Return False on fail, True on success.
********************************************************************/
-BOOL set_share_mode(int fnum,int mode)
+BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
{
- pstring fname;
- int fd2;
- char buf[16];
- int pid = (int)getpid();
-
- if (!share_name_fnum(fnum,fname)) return(False);
-
- {
- 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);
- }
-
- SIVAL(buf,0,Files[fnum].open_time);
- SIVAL(buf,4,mode);
- SIVAL(buf,8,pid);
- SIVAL(buf,12,LOCKING_VERSION);
-
- if (write(fd2,buf,16) != 16) {
- close(fd2);
- unlink(fname);
- return(False);
- }
-
- write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+ return share_ops->set_entry(token, fsp, port, op_type);
+}
- close(fd2);
+/*******************************************************************
+ Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+BOOL remove_share_oplock(files_struct *fsp, int token)
+{
+ return share_ops->remove_oplock(fsp, token);
+}
- DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
+/*******************************************************************
+ Call the specified function on each entry under management by the
+ share mode system.
+********************************************************************/
- return(True);
+int share_mode_forall(void (*fn)(share_mode_entry *, char *))
+{
+ return share_ops->forall(fn);
}
-
/*******************************************************************
-cleanup any stale share files
+ Dump the state of the system.
********************************************************************/
-void clean_share_files(void)
-{
- char *lockdir = lp_lockdir();
- void *dir;
- char *s;
-
- if (!*lockdir) return;
-
- dir = opendir(lockdir);
- if (!dir) return;
-
- while ((s=readdirname(dir))) {
- char buf[16];
- int pid;
- 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) {
- close(fd);
- if (!unlink(lname))
- printf("Deleted corrupt share file %s\n",s);
- continue;
- }
- close(fd);
-
- pid = IVAL(buf,8);
-
- if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
- if (!unlink(lname))
- printf("Deleted stale share file %s\n",s);
- }
- }
- closedir(dir);
+void share_status(FILE *f)
+{
+ share_ops->status(f);
}
diff --git a/source/locking/locking_shm.c b/source/locking/locking_shm.c
new file mode 100644
index 00000000000..1077cf23eb6
--- /dev/null
+++ b/source/locking/locking_shm.c
@@ -0,0 +1,701 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ shared memory locking 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.
+
+ 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.
+
+ October 1997 - split into separate file (tridge)
+*/
+
+#include "includes.h"
+
+#ifdef FAST_SHARE_MODES
+
+extern int DEBUGLEVEL;
+
+static struct shmem_ops *shmops;
+
+/* share mode record pointed to in shared memory hash bucket */
+typedef struct
+{
+ int next_offset; /* offset of next record in chain from hash bucket */
+ int locking_version;
+ SMB_DEV_T st_dev;
+ SMB_INO_T st_ino;
+ int num_share_mode_entries;
+ int share_mode_entries; /* Chain of share mode entries for this file */
+ char file_name[1];
+} share_mode_record;
+
+/* share mode entry pointed to by share_mode_record struct */
+typedef struct
+{
+ int next_share_mode_entry;
+ share_mode_entry e;
+} shm_share_mode_entry;
+
+static int read_only;
+
+
+/* Conversion to hash entry index from device and inode numbers. */
+#define HASH_ENTRY(dev,ino) ((unsigned int)(((dev) ^ (ino)) % shmops->hash_size()))
+
+
+/*******************************************************************
+ deinitialize the shared memory for share_mode management
+ ******************************************************************/
+static BOOL shm_stop_share_mode_mgmt(void)
+{
+ return shmops->shm_close();
+}
+
+/*******************************************************************
+ lock a hash bucket entry in shared memory for share_mode management
+ ******************************************************************/
+static BOOL shm_lock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
+{
+ return shmops->lock_hash_entry(HASH_ENTRY(dev, inode));
+}
+
+/*******************************************************************
+ unlock a hash bucket entry in shared memory for share_mode management
+ ******************************************************************/
+static BOOL shm_unlock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int token)
+{
+ return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode));
+}
+
+/*******************************************************************
+get all share mode entries in shared memory for a dev/inode pair.
+********************************************************************/
+static int shm_get_share_modes(connection_struct *conn,
+ int token, SMB_DEV_T dev, SMB_INO_T inode,
+ share_mode_entry **old_shares)
+{
+ int *mode_array;
+ unsigned int hash_entry = HASH_ENTRY(dev, inode);
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *entry_scanner_p;
+ shm_share_mode_entry *entry_prev_p;
+ int num_entries;
+ int num_entries_copied;
+ BOOL found = False;
+ share_mode_entry *share_array = (share_mode_entry *)0;
+
+ *old_shares = 0;
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ if(mode_array[hash_entry] == 0)
+ {
+ DEBUG(5,("get_share_modes hash bucket %d empty\n", hash_entry));
+ return 0;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(
+ file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(5,("get_share_modes no entry for file dev = %x ino = %.0f\n",
+ (unsigned int)dev, (double)inode));
+ return (0);
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: get_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
+ file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
+
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->shm_free(shmops->addr2offset(file_scanner_p));
+ return (0);
+ }
+
+ /* Allocate the old_shares array */
+ num_entries = file_scanner_p->num_share_mode_entries;
+ if(num_entries)
+ {
+ *old_shares = share_array = (share_mode_entry *)
+ malloc(num_entries * sizeof(share_mode_entry));
+ if(*old_shares == 0)
+ {
+ DEBUG(0,("get_share_modes: malloc fail!\n"));
+ return 0;
+ }
+ }
+
+ num_entries_copied = 0;
+
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ int pid = entry_scanner_p->e.pid;
+
+ if (pid && !process_exists(pid))
+ {
+ /* Delete this share mode entry */
+ shm_share_mode_entry *delete_entry_p = entry_scanner_p;
+
+ if(entry_prev_p == entry_scanner_p)
+ {
+ /* We are at start of list */
+ file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ }
+ else
+ {
+ entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
+ entry_scanner_p = (shm_share_mode_entry*)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ /* Decrement the number of share mode entries on this share mode record */
+ file_scanner_p->num_share_mode_entries -= 1;
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR: get_share_mode: entries=%d dev=%x ino=%.0f\n",
+ file_scanner_p->num_share_mode_entries, (unsigned int)dev, (double)inode));
+ return 0;
+ }
+
+ DEBUG(0,("get_share_modes: process %d no longer exists\n", pid));
+
+ shmops->shm_free(shmops->addr2offset(delete_entry_p));
+ }
+ else
+ {
+ /* This is a valid share mode entry and the process that
+ created it still exists. Copy it into the output array.
+ */
+ share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
+ share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
+ share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
+ share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
+ memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
+ sizeof(struct timeval));
+ num_entries_copied++;
+ DEBUG(5,("get_share_modes Read share mode 0x%X pid=%d\n",
+ entry_scanner_p->e.share_mode, entry_scanner_p->e.pid));
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (shm_share_mode_entry *)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ /* If no valid share mode entries were found then this record shouldn't exist ! */
+ if(num_entries_copied == 0)
+ {
+ DEBUG(0,("get_share_modes: file with dev %x inode %.0f empty\n",
+ (unsigned int)dev, (double)inode));
+
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->shm_free(shmops->addr2offset(file_scanner_p));
+ }
+
+ DEBUG(5,("get_share_modes: file with dev %x inode %.0f -> %d entries\n",
+ (unsigned int)dev, (double)inode, num_entries_copied));
+
+ return(num_entries_copied);
+}
+
+/*******************************************************************
+del the share mode of a file.
+********************************************************************/
+static void shm_del_share_mode(int token, files_struct *fsp)
+{
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ int *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *entry_scanner_p;
+ shm_share_mode_entry *entry_prev_p;
+ BOOL found = False;
+ int pid = getpid();
+
+ dev = fsp->fd_ptr->dev;
+ inode = fsp->fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ if(mode_array[hash_entry] == 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode hash bucket %d empty\n",
+ hash_entry));
+ return;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR: del_share_mode no entry for dev %x inode %.0f\n",
+ (unsigned int)dev, (double)inode));
+ return;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: del_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
+ file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
+
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->shm_free(shmops->addr2offset(file_scanner_p));
+ return;
+ }
+
+ found = False;
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ if( (pid == entry_scanner_p->e.pid) &&
+ (memcmp(&entry_scanner_p->e.time,
+ &fsp->open_time,sizeof(struct timeval)) == 0) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (shm_share_mode_entry *)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ if (found)
+ {
+ /* Decrement the number of entries in the record. */
+ file_scanner_p->num_share_mode_entries -= 1;
+
+ DEBUG(2,("del_share_modes Deleting share mode entry dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode));
+
+ if(entry_prev_p == entry_scanner_p)
+ /* We are at start of list */
+ file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
+ else
+ entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
+ shmops->shm_free(shmops->addr2offset(entry_scanner_p));
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode num_share_mode_entries=%d\n",
+ file_scanner_p->num_share_mode_entries));
+ return;
+ }
+
+ /* If we deleted the last share mode entry then remove the share mode record. */
+ if(file_scanner_p->num_share_mode_entries == 0)
+ {
+ DEBUG(2,("del_share_modes num entries = 0, deleting share_mode dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode));
+
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->shm_free(shmops->addr2offset(file_scanner_p));
+ }
+ }
+ else
+ {
+ DEBUG(0,("ERROR: del_share_modes No share mode dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode));
+ }
+}
+
+/*******************************************************************
+set the share mode of a file. Return False on fail, True on success.
+********************************************************************/
+static BOOL shm_set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
+{
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ int *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ shm_share_mode_entry *new_entry_p;
+ int new_entry_offset;
+ BOOL found = False;
+
+ dev = fsp->fd_ptr->dev;
+ inode = fsp->fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ /* We must create a share_mode_record */
+ share_mode_record *new_mode_p = NULL;
+ int new_offset = shmops->shm_alloc(sizeof(share_mode_record) +
+ strlen(fsp->fsp_name) + 1);
+ if(new_offset == 0) {
+ DEBUG(0,("ERROR:set_share_mode shmops->shm_alloc fail!\n"));
+ return False;
+ }
+ new_mode_p = shmops->offset2addr(new_offset);
+ new_mode_p->locking_version = LOCKING_VERSION;
+ new_mode_p->st_dev = dev;
+ new_mode_p->st_ino = inode;
+ new_mode_p->num_share_mode_entries = 0;
+ new_mode_p->share_mode_entries = 0;
+ pstrcpy(new_mode_p->file_name, fsp->fsp_name);
+
+ /* Chain onto the start of the hash chain (in the hope we will be used first). */
+ new_mode_p->next_offset = mode_array[hash_entry];
+ mode_array[hash_entry] = new_offset;
+
+ file_scanner_p = new_mode_p;
+
+ DEBUG(3,("set_share_mode: Created share record for %s (dev %x inode %.0f)\n",
+ fsp->fsp_name, (unsigned int)dev, (double)inode));
+ }
+
+ /* Now create the share mode entry */
+ new_entry_offset = shmops->shm_alloc(sizeof(shm_share_mode_entry));
+ if(new_entry_offset == 0) {
+ int delete_offset = mode_array[hash_entry];
+ DEBUG(0,("ERROR:set_share_mode: shmops->shm_alloc fail 1!\n"));
+ /* Unlink the damaged record */
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ /* And delete it */
+ shmops->shm_free( delete_offset );
+ return False;
+ }
+
+ new_entry_p = shmops->offset2addr(new_entry_offset);
+
+ new_entry_p->e.pid = getpid();
+ new_entry_p->e.share_mode = fsp->share_mode;
+ new_entry_p->e.op_port = port;
+ new_entry_p->e.op_type = op_type;
+ memcpy( (char *)&new_entry_p->e.time, (char *)&fsp->open_time, sizeof(struct timeval));
+
+ /* Chain onto the share_mode_record */
+ new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
+ file_scanner_p->share_mode_entries = new_entry_offset;
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:set_share_mode num_share_mode_entries=%d\n",
+ file_scanner_p->num_share_mode_entries));
+ return False;
+ }
+
+ /* Increment the share_mode_entries counter */
+ file_scanner_p->num_share_mode_entries += 1;
+
+ DEBUG(3,("set_share_mode: Created share entry for %s with mode 0x%X pid=%d\n",
+ fsp->fsp_name, fsp->share_mode, new_entry_p->e.pid));
+
+ return(True);
+}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
+{
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ int *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ shm_share_mode_entry *entry_scanner_p;
+ BOOL found = False;
+ int pid = getpid();
+
+ dev = fsp->fd_ptr->dev;
+ inode = fsp->fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ if(mode_array[hash_entry] == 0)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock: hash bucket %d empty\n",
+ hash_entry));
+ return False;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
+
+ while(file_scanner_p)
+ {
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR:remove_share_oplock: no entry found for dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode));
+ return False;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: Deleting old share mode v1=%d dev=%x ino=%.0f\n",
+ file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
+
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ else
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ shmops->shm_free(shmops->addr2offset(file_scanner_p));
+ return False;
+ }
+
+ found = False;
+ entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
+ file_scanner_p->share_mode_entries);
+ while(entry_scanner_p)
+ {
+ if( (pid == entry_scanner_p->e.pid) &&
+ (entry_scanner_p->e.share_mode == fsp->share_mode) &&
+ (memcmp(&entry_scanner_p->e.time,
+ &fsp->open_time,sizeof(struct timeval)) == 0) )
+ {
+ /* Delete the oplock info. */
+ entry_scanner_p->e.op_port = 0;
+ entry_scanner_p->e.op_type = 0;
+ found = True;
+ break;
+ }
+ else
+ {
+ entry_scanner_p = (shm_share_mode_entry *)
+ shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: No oplock granted. dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode));
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+call the specified function on each entry under management by the
+share mode system
+********************************************************************/
+static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
+{
+ int i, count=0;
+ int *mode_array;
+ share_mode_record *file_scanner_p;
+
+ mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
+
+ for( i = 0; i < shmops->hash_size(); i++) {
+ shmops->lock_hash_entry(i);
+ if(mode_array[i] == 0) {
+ shmops->unlock_hash_entry(i);
+ continue;
+ }
+
+ file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
+ while((file_scanner_p != 0) &&
+ (file_scanner_p->num_share_mode_entries != 0)) {
+ shm_share_mode_entry *entry_scanner_p =
+ (shm_share_mode_entry *)
+ shmops->offset2addr(file_scanner_p->share_mode_entries);
+
+ while(entry_scanner_p != 0) {
+
+ if (process_exists(entry_scanner_p->e.pid)) {
+ fn(&entry_scanner_p->e,
+ file_scanner_p->file_name);
+ count++;
+ }
+
+ entry_scanner_p =
+ (shm_share_mode_entry *)
+ shmops->offset2addr(
+ entry_scanner_p->next_share_mode_entry);
+ } /* end while entry_scanner_p */
+ file_scanner_p = (share_mode_record *)
+ shmops->offset2addr(file_scanner_p->next_offset);
+ } /* end while file_scanner_p */
+ shmops->unlock_hash_entry(i);
+ } /* end for */
+
+ return count;
+}
+
+
+/*******************************************************************
+dump the state of the system
+********************************************************************/
+static void shm_share_status(FILE *f)
+{
+ int bytes_free, bytes_used, bytes_overhead, bytes_total;
+
+ shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
+ bytes_total = bytes_free + bytes_used + bytes_overhead;
+
+ fprintf(f, "Share mode memory usage (bytes):\n");
+ fprintf(f, " %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
+ bytes_free, (bytes_free * 100)/bytes_total,
+ bytes_used, (bytes_used * 100)/bytes_total,
+ bytes_overhead, (bytes_overhead * 100)/bytes_total,
+ bytes_total);
+}
+
+
+static struct share_ops share_ops = {
+ shm_stop_share_mode_mgmt,
+ shm_lock_share_entry,
+ shm_unlock_share_entry,
+ shm_get_share_modes,
+ shm_del_share_mode,
+ shm_set_share_mode,
+ shm_remove_share_oplock,
+ shm_share_forall,
+ shm_share_status,
+};
+
+/*******************************************************************
+ initialize the shared memory for share_mode management
+ ******************************************************************/
+struct share_ops *locking_shm_init(int ronly)
+{
+ read_only = ronly;
+
+#ifdef HAVE_SYSV_IPC
+ shmops = sysv_shm_open(read_only);
+ if (shmops) return &share_ops;
+#endif
+
+#ifdef HAVE_SHARED_MMAP
+ shmops = smb_shm_open(read_only);
+ if (shmops) return &share_ops;
+#endif
+
+ return NULL;
+}
+
+#else
+ int locking_shm_dummy_procedure(void)
+{return 0;}
+#endif /* FAST_SHARE_MODES */
diff --git a/source/locking/locking_slow.c b/source/locking/locking_slow.c
new file mode 100644
index 00000000000..fd95fd45ec2
--- /dev/null
+++ b/source/locking/locking_slow.c
@@ -0,0 +1,1076 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ slow (lockfile) locking 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.
+
+ 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.
+
+ October 1997 - split into separate file (tridge)
+*/
+
+#include "includes.h"
+
+#ifndef FAST_SHARE_MODES
+
+extern int DEBUGLEVEL;
+
+/*
+ * Locking file header lengths & offsets.
+ */
+#define SMF_VERSION_OFFSET 0
+#define SMF_NUM_ENTRIES_OFFSET 4
+#define SMF_FILENAME_LEN_OFFSET 8
+#define SMF_HEADER_LENGTH 10
+
+#define SMF_ENTRY_LENGTH 20
+
+/*
+ * Share mode record offsets.
+ */
+
+#define SME_SEC_OFFSET 0
+#define SME_USEC_OFFSET 4
+#define SME_SHAREMODE_OFFSET 8
+#define SME_PID_OFFSET 12
+#define SME_PORT_OFFSET 16
+#define SME_OPLOCK_TYPE_OFFSET 18
+
+/* we need world read for smbstatus to function correctly */
+#ifdef SECURE_SHARE_MODES
+#define SHARE_FILE_MODE 0600
+#else
+#define SHARE_FILE_MODE 0644
+#endif
+
+static int read_only;
+
+/*******************************************************************
+ deinitialize share_mode management
+ ******************************************************************/
+static BOOL slow_stop_share_mode_mgmt(void)
+{
+ return True;
+}
+
+
+/*******************************************************************
+ name a share file
+ ******************************************************************/
+static BOOL share_name(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, char *name)
+{
+ int len;
+ pstrcpy(name,lp_lockdir());
+ trim_string(name,"","/");
+ if (!*name) return(False);
+ len = strlen(name);
+ name += len;
+
+#ifdef LARGE_SMB_INO_T
+ slprintf(name, sizeof(pstring) - len - 1, "/share.%u.%.0f",(unsigned int)dev,(double)inode);
+#else /* LARGE_SMB_INO_T */
+ slprintf(name, sizeof(pstring) - len - 1, "/share.%u.%lu",(unsigned int)dev,(unsigned long)inode);
+#endif /* LARGE_SMB_INO_T */
+ return(True);
+}
+
+/*******************************************************************
+Force a share file to be deleted.
+********************************************************************/
+static int delete_share_file(connection_struct *conn, char *fname )
+{
+ if (read_only) return -1;
+
+ /* the share file could be owned by anyone, so do this as root */
+ become_root(False);
+
+ if(unlink(fname) != 0)
+ {
+ DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
+ fname, strerror(errno)));
+ }
+ else
+ {
+ DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
+ }
+
+ /* return to our previous privilage level */
+ unbecome_root(False);
+
+ return 0;
+}
+
+/*******************************************************************
+ lock a share mode file.
+ ******************************************************************/
+static BOOL slow_lock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
+{
+ pstring fname;
+ int fd;
+ int ret = True;
+
+ *ptok = (int)-1;
+
+ if(!share_name(conn, dev, inode, fname))
+ return False;
+
+ if (read_only) return True;
+
+ /* we need to do this as root */
+ become_root(False);
+
+ {
+ BOOL gotlock = False;
+ /*
+ * There was a race condition in the original slow share mode code.
+ * A smbd could open a share mode file, and before getting
+ * the lock, another smbd could delete the last entry for
+ * the share mode file and delete the file entry from the
+ * directory. Thus this smbd would be left with a locked
+ * share mode fd attached to a file that no longer had a
+ * directory entry. Thus another smbd would think that
+ * there were no outstanding opens on the file. To fix
+ * this we now check we can do a stat() call on the filename
+ * before allowing the lock to proceed, and back out completely
+ * and try the open again if we cannot.
+ * Jeremy Allison (jallison@whistle.com).
+ */
+
+ do
+ {
+ SMB_STRUCT_STAT dummy_stat;
+
+ fd = (int)open(fname,read_only?O_RDONLY:(O_RDWR|O_CREAT),
+ SHARE_FILE_MODE);
+
+ if(fd < 0)
+ {
+ DEBUG(0,("ERROR lock_share_entry: failed to open share file %s. Error was %s\n",
+ fname, strerror(errno)));
+ ret = False;
+ break;
+ }
+
+ /* At this point we have an open fd to the share mode file.
+ Lock the first byte exclusively to signify a lock. */
+ if(fcntl_lock(fd, SMB_F_SETLKW, 0, 1, F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR lock_share_entry: fcntl_lock on file %s failed with %s\n",
+ fname, strerror(errno)));
+ close(fd);
+ ret = False;
+ break;
+ }
+
+ /*
+ * If we cannot stat the filename, the file was deleted between
+ * the open and the lock call. Back out and try again.
+ */
+
+ if(sys_stat(fname, &dummy_stat)!=0)
+ {
+ DEBUG(2,("lock_share_entry: Re-issuing open on %s to fix race. Error was %s\n",
+ fname, strerror(errno)));
+ close(fd);
+ }
+ else
+ gotlock = True;
+ } while(!gotlock);
+
+ /*
+ * We have to come here if any of the above calls fail
+ * as we don't want to return and leave ourselves running
+ * as root !
+ */
+ }
+
+ *ptok = (int)fd;
+
+ /* return to our previous privilage level */
+ unbecome_root(False);
+
+ return ret;
+}
+
+/*******************************************************************
+ unlock a share mode file.
+ ******************************************************************/
+static BOOL slow_unlock_share_entry(connection_struct *conn,
+ SMB_DEV_T dev, SMB_INO_T inode, int token)
+{
+ int fd = token;
+ int ret = True;
+ SMB_STRUCT_STAT sb;
+ pstring fname;
+
+ if (read_only) return True;
+
+ /* Fix for zero length share files from
+ Gerald Werner <wernerg@mfldclin.edu> */
+
+ share_name(conn, dev, inode, fname);
+
+ /* get the share mode file size */
+ if(sys_fstat((int)token, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: unlock_share_entry: Failed to do stat on share file %s (%s)\n",
+ fname, strerror(errno)));
+ sb.st_size = 1;
+ ret = False;
+ }
+
+ /* If the file was zero length, we must delete before
+ doing the unlock to avoid a race condition (see
+ the code in lock_share_mode_entry for details.
+ */
+
+ /* remove the share file if zero length */
+ if(sb.st_size == 0)
+ delete_share_file(conn, fname);
+
+ /* token is the fd of the open share mode file. */
+ /* Unlock the first byte. */
+ if(fcntl_lock(fd, SMB_F_SETLKW, 0, 1, F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
+ strerror(errno)));
+ ret = False;
+ }
+
+ close(fd);
+ return ret;
+}
+
+/*******************************************************************
+Read a share file into a buffer.
+********************************************************************/
+static int read_share_file(connection_struct *conn, int fd, char *fname, char **out, BOOL *p_new_file)
+{
+ SMB_STRUCT_STAT sb;
+ char *buf;
+ SMB_OFF_T size;
+
+ *out = 0;
+ *p_new_file = False;
+
+ if(sys_fstat(fd, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
+ fname, strerror(errno)));
+ return -1;
+ }
+
+ if(sb.st_size == 0)
+ {
+ *p_new_file = True;
+ return 0;
+ }
+
+ /* Allocate space for the file */
+ if((buf = (char *)malloc((size_t)sb.st_size)) == NULL)
+ {
+ DEBUG(0,("read_share_file: malloc for file size %d fail !\n",
+ (int)sb.st_size));
+ return -1;
+ }
+
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to reset position to 0 \
+for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return -1;
+ }
+
+ if (read(fd,buf,(size_t)sb.st_size) != (size_t)sb.st_size)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to read share file %s (%s)\n",
+ fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return -1;
+ }
+
+ if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) {
+ DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname,
+ IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION));
+ if(buf)
+ free(buf);
+ delete_share_file(conn, fname);
+ return -1;
+ }
+
+ /* Sanity check for file contents */
+ size = sb.st_size;
+ size -= SMF_HEADER_LENGTH; /* Remove the header */
+
+ /* Remove the filename component. */
+ size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
+
+ /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+ if((size % SMF_ENTRY_LENGTH) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: share file %s is an incorrect length - \
+deleting it.\n", fname));
+ if(buf)
+ free(buf);
+ delete_share_file(conn, fname);
+ return -1;
+ }
+
+ *out = buf;
+ return 0;
+}
+
+/*******************************************************************
+get all share mode entries in a share file for a dev/inode pair.
+********************************************************************/
+static int slow_get_share_modes(connection_struct *conn, int token,
+ SMB_DEV_T dev, SMB_INO_T inode,
+ share_mode_entry **old_shares)
+{
+ int fd = token;
+ pstring fname;
+ int i;
+ int num_entries;
+ int num_entries_copied;
+ int newsize;
+ share_mode_entry *share_array;
+ char *buf = 0;
+ char *base = 0;
+ BOOL new_file;
+
+ *old_shares = 0;
+
+ /* Read the share file header - this is of the form:
+ 0 - locking version.
+ 4 - number of share mode entries.
+ 8 - 2 byte name length
+ [n bytes] file name (zero terminated).
+
+ Followed by <n> share mode entries of the form :
+
+ 0 - tv_sec
+ 4 - tv_usec
+ 8 - share_mode
+ 12 - pid
+ 16 - oplock port (if oplocks in use) - 2 bytes.
+ */
+
+ share_name(conn, dev, inode, fname);
+
+ if(read_share_file( conn, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
+ fname));
+ return 0;
+ }
+
+ if(new_file == True)
+ return 0;
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("get_share_modes: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:get_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %s\n", num_entries, fname));
+ return 0;
+ }
+
+ if(num_entries)
+ {
+ *old_shares = share_array = (share_mode_entry *)
+ malloc(num_entries * sizeof(share_mode_entry));
+ if(*old_shares == 0)
+ {
+ DEBUG(0,("get_share_modes: malloc fail !\n"));
+ return 0;
+ }
+ }
+ else
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("get_share_modes: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(conn, fname);
+ return 0;
+ }
+
+ num_entries_copied = 0;
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for( i = 0; i < num_entries; i++)
+ {
+ int pid;
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ pid = IVAL(p,SME_PID_OFFSET);
+
+ if(!process_exists(pid))
+ {
+ DEBUG(0,("get_share_modes: process %d no longer exists and \
+it left a share mode entry with mode 0x%X in share file %s\n",
+ pid, IVAL(p,SME_SHAREMODE_OFFSET), fname));
+ continue;
+ }
+ share_array[num_entries_copied].time.tv_sec = IVAL(p,SME_SEC_OFFSET);
+ share_array[num_entries_copied].time.tv_usec = IVAL(p,SME_USEC_OFFSET);
+ share_array[num_entries_copied].share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+ share_array[num_entries_copied].pid = pid;
+ share_array[num_entries_copied].op_port = SVAL(p,SME_PORT_OFFSET);
+ share_array[num_entries_copied].op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+
+ num_entries_copied++;
+ }
+
+ if(num_entries_copied == 0)
+ {
+ /* Delete the whole file. */
+ DEBUG(0,("get_share_modes: share file %s had no valid entries - deleting it !\n",
+ fname));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ delete_share_file(conn, fname);
+ return 0;
+ }
+
+ /* If we deleted some entries we need to re-write the whole number of
+ share mode entries back into the file. */
+
+ if(num_entries_copied != num_entries)
+ {
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ return 0;
+ }
+
+ SIVAL(buf, SMF_NUM_ENTRIES_OFFSET, num_entries_copied);
+ for( i = 0; i < num_entries_copied; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ SIVAL(p,SME_PID_OFFSET,share_array[i].pid);
+ SIVAL(p,SME_SHAREMODE_OFFSET,share_array[i].share_mode);
+ SIVAL(p,SME_SEC_OFFSET,share_array[i].time.tv_sec);
+ SIVAL(p,SME_USEC_OFFSET,share_array[i].time.tv_usec);
+ SSVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
+ }
+
+ newsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries_copied);
+ if(write(fd, buf, newsize) != newsize)
+ {
+ DEBUG(0,("ERROR: get_share_modes: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ return 0;
+ }
+ /* Now truncate the file at this point. */
+ if(sys_ftruncate(fd, (SMB_OFF_T)newsize)!= 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+ if(*old_shares)
+ free((char *)*old_shares);
+ *old_shares = 0;
+ if(buf)
+ free(buf);
+ return 0;
+ }
+ }
+
+ if(buf)
+ free(buf);
+
+ DEBUG(5,("get_share_modes: Read share file %s returning %d entries\n",fname,
+ num_entries_copied));
+
+ return num_entries_copied;
+}
+
+/*******************************************************************
+del a share mode from a share mode file.
+********************************************************************/
+static void slow_del_share_mode(int token, files_struct *fsp)
+{
+ pstring fname;
+ int fd = (int)token;
+ char *buf = 0;
+ char *base = 0;
+ int num_entries;
+ int newsize;
+ int i;
+ int pid;
+ BOOL deleted = False;
+ BOOL new_file;
+
+ share_name(fsp->conn, fsp->fd_ptr->dev,
+ fsp->fd_ptr->inode, fname);
+
+ if(read_share_file( fsp->conn, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
+ fname));
+ return;
+ }
+
+ if(new_file == True)
+ {
+ DEBUG(0,("ERROR:del_share_mode: share file %s is new (size zero), deleting it.\n",
+ fname));
+ delete_share_file(fsp->conn, fname);
+ return;
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %s\n", num_entries, fname));
+ return;
+ }
+
+ if(num_entries == 0)
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("del_share_mode: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fsp->conn, fname);
+ return;
+ }
+
+ pid = getpid();
+
+ /* Go through the entries looking for the particular one
+ we have set - delete it.
+ */
+
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for(i = 0; i < num_entries; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ if((IVAL(p,SME_SEC_OFFSET) != fsp->open_time.tv_sec) ||
+ (IVAL(p,SME_USEC_OFFSET) != fsp->open_time.tv_usec) ||
+ (IVAL(p,SME_SHAREMODE_OFFSET) != fsp->share_mode) ||
+ (IVAL(p,SME_PID_OFFSET) != pid))
+ continue;
+
+ DEBUG(5,("del_share_mode: deleting entry number %d (of %d) from the share file %s\n",
+ i, num_entries, fname));
+
+ /* Remove this entry. */
+ if(i != num_entries - 1)
+ memcpy(p, p + SMF_ENTRY_LENGTH, (num_entries - i - 1)*SMF_ENTRY_LENGTH);
+
+ deleted = True;
+ break;
+ }
+
+ if(!deleted)
+ {
+ DEBUG(0,("del_share_mode: entry not found in share file %s\n", fname));
+ if(buf)
+ free(buf);
+ return;
+ }
+
+ num_entries--;
+ SIVAL(buf,SMF_NUM_ENTRIES_OFFSET, num_entries);
+
+ if(num_entries == 0)
+ {
+ /* Deleted the last entry - remove the file. */
+ DEBUG(5,("del_share_mode: removed last entry in share file - deleting share file %s\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fsp->conn,fname);
+ return;
+ }
+
+ /* Re-write the file - and truncate it at the correct point. */
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+
+ newsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
+ if(write(fd, buf, newsize) != newsize)
+ {
+ DEBUG(0,("ERROR: del_share_mode: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+
+ /* Now truncate the file at this point. */
+ if(sys_ftruncate(fd, (SMB_OFF_T)newsize) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+}
+
+/*******************************************************************
+set the share mode of a file
+********************************************************************/
+static BOOL slow_set_share_mode(int token,files_struct *fsp, uint16 port, uint16 op_type)
+{
+ pstring fname;
+ int fd = (int)token;
+ int pid = (int)getpid();
+ SMB_STRUCT_STAT sb;
+ char *buf;
+ int num_entries;
+ int header_size;
+ char *p;
+
+ share_name(fsp->conn, fsp->fd_ptr->dev,
+ fsp->fd_ptr->inode, fname);
+
+ if(sys_fstat(fd, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to do stat on share file %s\n",
+ fname));
+ return False;
+ }
+
+ /* Sanity check for file contents (if it's not a new share file). */
+ if(sb.st_size != 0)
+ {
+ SMB_OFF_T size = sb.st_size;
+
+ /* Allocate space for the file plus one extra entry */
+ if((buf = (char *)malloc((size_t)(sb.st_size + SMF_ENTRY_LENGTH))) == NULL)
+ {
+ DEBUG(0,("set_share_mode: malloc for file size %d fail !\n",
+ (int)(sb.st_size + SMF_ENTRY_LENGTH)));
+ return False;
+ }
+
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to reset position \
+to 0 for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (read(fd,buf,(size_t)sb.st_size) != (size_t)sb.st_size)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to read share file %s (%s)\n",
+ fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,SMF_VERSION_OFFSET),
+ LOCKING_VERSION));
+ if(buf)
+ free(buf);
+ delete_share_file(fsp->conn, fname);
+ return False;
+ }
+
+ size -= (SMF_HEADER_LENGTH + SVAL(buf, SMF_FILENAME_LEN_OFFSET)); /* Remove the header */
+
+ /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+ if((size % SMF_ENTRY_LENGTH) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: share file %s is an incorrect length - \
+deleting it.\n", fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fsp->conn, fname);
+ return False;
+ }
+
+ }
+ else
+ {
+ /* New file - just use a single_entry. */
+ if((buf = (char *)malloc(SMF_HEADER_LENGTH +
+ strlen(fsp->fsp_name) + 1 + SMF_ENTRY_LENGTH)) == NULL)
+ {
+ DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
+ return False;
+ }
+ SIVAL(buf,SMF_VERSION_OFFSET,LOCKING_VERSION);
+ SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,0);
+ SSVAL(buf,SMF_FILENAME_LEN_OFFSET,strlen(fsp->fsp_name) + 1);
+ pstrcpy(buf + SMF_HEADER_LENGTH, fsp->fsp_name);
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+ header_size = SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+ p = buf + header_size + (num_entries * SMF_ENTRY_LENGTH);
+ SIVAL(p,SME_SEC_OFFSET,fsp->open_time.tv_sec);
+ SIVAL(p,SME_USEC_OFFSET,fsp->open_time.tv_usec);
+ SIVAL(p,SME_SHAREMODE_OFFSET,fsp->share_mode);
+ SIVAL(p,SME_PID_OFFSET,pid);
+ SSVAL(p,SME_PORT_OFFSET,port);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,op_type);
+
+ num_entries++;
+
+ SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,num_entries);
+
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: (1) Failed to reset position to \
+0 for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (write(fd,buf,header_size + (num_entries*SMF_ENTRY_LENGTH)) !=
+ (header_size + (num_entries*SMF_ENTRY_LENGTH)))
+ {
+ DEBUG(2,("ERROR: set_share_mode: Failed to write share file %s - \
+deleting it (%s).\n",fname, strerror(errno)));
+ delete_share_file(fsp->conn, fname);
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ /* Now truncate the file at this point - just for safety. */
+
+ if(sys_ftruncate(fd, (SMB_OFF_T)(header_size + (SMF_ENTRY_LENGTH*num_entries)))!= 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, header_size + (SMF_ENTRY_LENGTH*num_entries),
+ strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if(buf)
+ free(buf);
+
+ DEBUG(3,("set_share_mode: Created share file %s with \
+mode 0x%X pid=%d\n",fname,fsp->share_mode,pid));
+
+ return True;
+}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+static BOOL slow_remove_share_oplock(files_struct *fsp, int token)
+{
+ pstring fname;
+ int fd = (int)token;
+ char *buf = 0;
+ char *base = 0;
+ int num_entries;
+ int fsize;
+ int i;
+ int pid;
+ BOOL found = False;
+ BOOL new_file;
+
+ share_name(fsp->conn, fsp->fd_ptr->dev,
+ fsp->fd_ptr->inode, fname);
+
+ if(read_share_file( fsp->conn, fd, fname, &buf, &new_file) != 0)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n",
+ fname));
+ return False;
+ }
+
+ if(new_file == True)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \
+deleting it.\n", fname));
+ delete_share_file(fsp->conn, fname);
+ return False;
+ }
+
+ num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+ DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \
+for share file %s\n", num_entries, fname));
+ return False;
+ }
+
+ if(num_entries == 0)
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fsp->conn, fname);
+ return False;
+ }
+
+ pid = getpid();
+
+ /* Go through the entries looking for the particular one
+ we have set - remove the oplock settings on it.
+ */
+
+ base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+ for(i = 0; i < num_entries; i++)
+ {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+
+ if((IVAL(p,SME_SEC_OFFSET) != fsp->open_time.tv_sec) ||
+ (IVAL(p,SME_USEC_OFFSET) != fsp->open_time.tv_usec) ||
+ (IVAL(p,SME_SHAREMODE_OFFSET) != fsp->share_mode) ||
+ (IVAL(p,SME_PID_OFFSET) != pid))
+ continue;
+
+ DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \
+from the share file %s\n", i, num_entries, fname));
+
+ SSVAL(p,SME_PORT_OFFSET,0);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0);
+ found = True;
+ break;
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ /* Re-write the file - and truncate it at the correct point. */
+ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
+ if(write(fd, buf, fsize) != fsize)
+ {
+ DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ return True;
+}
+
+
+
+/*******************************************************************
+call the specified function on each entry under management by the
+share ode system
+********************************************************************/
+static int slow_share_forall(void (*fn)(share_mode_entry *, char *))
+{
+ int i, count=0;
+ void *dir;
+ char *s;
+ share_mode_entry e;
+
+ dir = opendir(lp_lockdir());
+ if (!dir) {
+ return(0);
+ }
+
+ while ((s=readdirname(dir))) {
+ char *buf;
+ char *base;
+ int fd;
+ pstring lname;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ BOOL new_file;
+ pstring fname;
+
+#ifdef LARGE_SMB_INO_T
+ double inode_ascii;
+ if (sscanf(s,"share.%u.%lf",&dev,&inode_ascii)!=2) continue;
+ inode = (SMB_INO_T)inode_ascii;
+#else /* LARGE_SMB_INO_T */
+ unsigned long inode_long;
+ if (sscanf(s,"share.%u.%lu",&dev,&inode_long)!=2) continue;
+ inode = (SMB_INO_T)inode_long;
+#endif /* LARGE_SMB_INO_T */
+
+ pstrcpy(lname,lp_lockdir());
+ trim_string(lname,NULL,"/");
+ pstrcat(lname,"/");
+ pstrcat(lname,s);
+
+ fd = open(lname,read_only?O_RDONLY:O_RDWR,0);
+ if (fd < 0) {
+ continue;
+ }
+
+ /* Lock the share mode file while we read it. */
+ if(!read_only &&
+ fcntl_lock(fd, SMB_F_SETLKW, 0, 1, F_WRLCK) == False) {
+ close(fd);
+ continue;
+ }
+
+ if(read_share_file( 0, fd, lname, &buf, &new_file)) {
+ close(fd);
+ continue;
+ }
+ pstrcpy( fname, &buf[10]);
+ close(fd);
+
+ base = buf + SMF_HEADER_LENGTH +
+ SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+ for( i = 0; i < IVAL(buf, SMF_NUM_ENTRIES_OFFSET); i++) {
+ char *p = base + (i*SMF_ENTRY_LENGTH);
+ e.pid = IVAL(p,SME_PID_OFFSET);
+ e.share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+ e.time.tv_sec = IVAL(p,SME_SEC_OFFSET);
+ e.time.tv_usec = IVAL(p,SME_USEC_OFFSET);
+ e.op_port = SVAL(p,SME_PORT_OFFSET);
+ e.pid = SVAL(p,SME_PID_OFFSET);
+ e.op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+
+ if (process_exists(e.pid)) {
+ fn(&e, fname);
+ count++;
+ }
+ } /* end for i */
+
+ if(buf)
+ free(buf);
+ base = 0;
+ } /* end while */
+ closedir(dir);
+
+ return count;
+}
+
+
+/*******************************************************************
+dump the state of the system
+********************************************************************/
+static void slow_share_status(FILE *f)
+{
+
+}
+
+
+static struct share_ops share_ops = {
+ slow_stop_share_mode_mgmt,
+ slow_lock_share_entry,
+ slow_unlock_share_entry,
+ slow_get_share_modes,
+ slow_del_share_mode,
+ slow_set_share_mode,
+ slow_remove_share_oplock,
+ slow_share_forall,
+ slow_share_status,
+};
+
+/*******************************************************************
+ initialize the slow share_mode management
+ ******************************************************************/
+struct share_ops *locking_slow_init(int ronly)
+{
+
+ read_only = ronly;
+
+ if (!directory_exist(lp_lockdir(),NULL)) {
+ if (!read_only)
+ mkdir(lp_lockdir(),0755);
+ if (!directory_exist(lp_lockdir(),NULL))
+ return NULL;
+ }
+
+ return &share_ops;
+}
+#else
+ int locking_slow_dummy_procedure(void)
+{return 0;}
+#endif /* !FAST_SHARE_MODES */
diff --git a/source/locking/shmem.c b/source/locking/shmem.c
new file mode 100644
index 00000000000..b63db1f168d
--- /dev/null
+++ b/source/locking/shmem.c
@@ -0,0 +1,893 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Shared memory functions
+ Copyright (C) Erik Devriendt 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 HAVE_SHARED_MMAP
+
+
+extern int DEBUGLEVEL;
+
+
+#define SMB_SHM_MAGIC 0x53484100
+/* = "SHM" in hex */
+
+#define SMB_SHM_VERSION 2
+
+/* we need world read for smbstatus to function correctly */
+#ifdef SECURE_SHARE_MODES
+#define SHM_FILE_MODE 0600
+#else
+#define SHM_FILE_MODE 0644
+#endif
+
+#define SHMEM_HASH_SIZE 13
+
+
+/* WARNING : offsets are used because mmap() does not guarantee that all processes have the
+ shared memory mapped to the same address */
+
+struct SmbShmHeader
+{
+ int smb_shm_magic;
+ int smb_shm_version;
+ int total_size; /* in bytes */
+ BOOL consistent;
+ int first_free_off;
+ int userdef_off; /* a userdefined offset. can be used to store root of tree or list */
+ struct { /* a cell is a range of bytes of sizeof(struct SmbShmBlockDesc) size */
+ int cells_free;
+ int cells_used;
+ int cells_system; /* number of cells used as allocated block descriptors */
+ } statistics;
+};
+
+#define SMB_SHM_NOT_FREE_OFF (-1)
+struct SmbShmBlockDesc
+{
+ int next; /* offset of next block in the free list or SMB_SHM_NOT_FREE_OFF when block in use */
+ int size; /* user size in BlockDescSize units */
+};
+
+#define EOList_Addr (struct SmbShmBlockDesc *)( 0 )
+#define EOList_Off 0
+
+#define CellSize sizeof(struct SmbShmBlockDesc)
+
+/* HeaderSize aligned on 8 byte boundary */
+#define AlignedHeaderSize ((sizeof(struct SmbShmHeader)+7) & ~7)
+
+static int smb_shm_fd = -1;
+static pstring smb_shm_processreg_name = "";
+
+static struct SmbShmHeader *smb_shm_header_p = (struct SmbShmHeader *)0;
+static int smb_shm_times_locked = 0;
+
+static BOOL smb_shm_initialize_called = False;
+
+static int read_only;
+
+static BOOL smb_shm_global_lock(void)
+{
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_global_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ smb_shm_times_locked++;
+
+ if(smb_shm_times_locked > 1)
+ {
+ DEBUG(5,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
+ return True;
+ }
+
+ if (read_only)
+ return True;
+
+ /* Do an exclusive wait lock on the first byte of the file */
+ if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, 0, 1, F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %s\n",strerror(errno)));
+ smb_shm_times_locked--;
+ return False;
+ }
+
+ return True;
+
+}
+
+static BOOL smb_shm_global_unlock(void)
+{
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ if(smb_shm_times_locked == 0)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : shmem not locked\n"));
+ return False;
+ }
+
+ smb_shm_times_locked--;
+
+ if(smb_shm_times_locked > 0)
+ {
+ DEBUG(5,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
+ return True;
+ }
+
+ if (read_only)
+ return True;
+
+ /* Do a wait unlock on the first byte of the file */
+ if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, 0, 1, F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %s\n",strerror(errno)));
+ smb_shm_times_locked++;
+ return False;
+ }
+
+ return True;
+
+}
+
+
+static void *smb_shm_offset2addr(int offset)
+{
+ if (offset == 0 )
+ return (void *)(0);
+
+ if (!smb_shm_header_p)
+ return (void *)(0);
+
+ return (void *)((char *)smb_shm_header_p + offset );
+}
+
+static int smb_shm_addr2offset(void *addr)
+{
+ if (!addr)
+ return 0;
+
+ if (!smb_shm_header_p)
+ return 0;
+
+ return (int)((char *)addr - (char *)smb_shm_header_p);
+}
+
+
+
+static int smb_shm_alloc(int size)
+{
+ unsigned num_cells ;
+ struct SmbShmBlockDesc *scanner_p;
+ struct SmbShmBlockDesc *prev_p;
+ struct SmbShmBlockDesc *new_p;
+ int result_offset;
+
+
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n"));
+ return 0;
+ }
+
+ smb_shm_global_lock();
+
+ if( !smb_shm_header_p->consistent)
+ {
+ DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n"));
+ smb_shm_global_unlock();
+ return 0;
+ }
+
+
+ /* calculate the number of cells */
+ num_cells = (size + CellSize -1) / CellSize;
+
+ /* set start of scan */
+ prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ /* scan the free list to find a matching free space */
+ while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) )
+ {
+ prev_p = scanner_p;
+ scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
+ }
+
+ /* at this point scanner point to a block header or to the end of the list */
+ if ( scanner_p == EOList_Addr )
+ {
+ DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size));
+ smb_shm_global_unlock();
+ return (0);
+ }
+
+ /* going to modify shared mem */
+ smb_shm_header_p->consistent = False;
+
+ /* if we found a good one : scanner == the good one */
+ if ( scanner_p->size <= num_cells + 2 )
+ {
+ /* there is no use in making a new one, it will be too small anyway
+ * we will link out scanner
+ */
+ if ( prev_p == scanner_p )
+ {
+ smb_shm_header_p->first_free_off = scanner_p->next ;
+ }
+ else
+ {
+ prev_p->next = scanner_p->next ;
+ }
+ smb_shm_header_p->statistics.cells_free -= scanner_p->size;
+ smb_shm_header_p->statistics.cells_used += scanner_p->size;
+ }
+ else
+ {
+ /* Make a new one */
+ new_p = scanner_p + 1 + num_cells;
+ new_p->size = scanner_p->size - num_cells - 1;
+ new_p->next = scanner_p->next;
+ scanner_p->size = num_cells;
+ scanner_p->next = smb_shm_addr2offset(new_p);
+
+ if ( prev_p != scanner_p )
+ {
+ prev_p->next = smb_shm_addr2offset(new_p) ;
+ }
+ else
+ {
+ smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p) ;
+ }
+ smb_shm_header_p->statistics.cells_free -= num_cells+1;
+ smb_shm_header_p->statistics.cells_used += num_cells;
+ smb_shm_header_p->statistics.cells_system += 1;
+ }
+
+ result_offset = smb_shm_addr2offset( &(scanner_p[1]) );
+ scanner_p->next = SMB_SHM_NOT_FREE_OFF ;
+
+ /* end modification of shared mem */
+ smb_shm_header_p->consistent = True;
+
+ DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
+
+ smb_shm_global_unlock();
+ return ( result_offset );
+}
+
+
+
+
+/*
+ * Function to create the hash table for the share mode entries. Called
+ * when smb shared memory is global locked.
+ */
+static BOOL smb_shm_create_hash_table( unsigned int size )
+{
+ size *= sizeof(int);
+
+ smb_shm_global_lock();
+ smb_shm_header_p->userdef_off = smb_shm_alloc( size );
+
+ if(smb_shm_header_p->userdef_off == 0)
+ {
+ DEBUG(0,("smb_shm_create_hash_table: Failed to create hash table of size %d\n",size));
+ smb_shm_global_unlock();
+ return False;
+ }
+
+ /* Clear hash buckets. */
+ memset( smb_shm_offset2addr(smb_shm_header_p->userdef_off), '\0', size);
+ smb_shm_global_unlock();
+ return True;
+}
+
+static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *other_processes)
+{
+ int smb_shm_processes_fd = -1;
+ int nb_read;
+ pid_t other_pid;
+ SMB_OFF_T seek_back = -((SMB_OFF_T)sizeof(other_pid));
+ SMB_OFF_T free_slot = -1;
+ SMB_OFF_T erased_slot;
+
+ smb_shm_processes_fd = open(processreg_file,
+ read_only?O_RDONLY:(O_RDWR|O_CREAT),
+ SHM_FILE_MODE);
+
+ if ( smb_shm_processes_fd < 0 )
+ {
+ DEBUG(0,("ERROR smb_shm_register_process : processreg_file open failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ *other_processes = False;
+
+ while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
+ {
+ if(other_pid)
+ {
+ if(process_exists(other_pid))
+ *other_processes = True;
+ else
+ {
+ /* erase old pid */
+ DEBUG(5,("smb_shm_register_process : erasing stale record for pid %d (seek_back = %.0f)\n",
+ (int)other_pid, (double)seek_back));
+ other_pid = (pid_t)0;
+ erased_slot = sys_lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
+ write(smb_shm_processes_fd, &other_pid, sizeof(other_pid));
+ if(free_slot < 0)
+ free_slot = erased_slot;
+ }
+ }
+ else
+ if(free_slot < 0)
+ free_slot = sys_lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
+ }
+ if (nb_read < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_register_process : processreg_file read failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ if(free_slot < 0)
+ free_slot = sys_lseek(smb_shm_processes_fd, 0, SEEK_END);
+
+ DEBUG(5,("smb_shm_register_process : writing record for pid %d at offset %.0f\n",
+ (int)pid, (double)free_slot));
+
+ sys_lseek(smb_shm_processes_fd, free_slot, SEEK_SET);
+ if(write(smb_shm_processes_fd, &pid, sizeof(pid)) < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_register_process : processreg_file write failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ close(smb_shm_processes_fd);
+
+ return True;
+}
+
+static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
+{
+ int smb_shm_processes_fd = -1;
+ int nb_read;
+ pid_t other_pid;
+ SMB_OFF_T seek_back = -((SMB_OFF_T)sizeof(other_pid));
+ BOOL found = False;
+
+
+ smb_shm_processes_fd = open(processreg_file, O_RDWR);
+ if ( smb_shm_processes_fd < 0 )
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file open failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
+ {
+ DEBUG(5,("smb_shm_unregister_process : read record for pid %d\n",(int)other_pid));
+ if(other_pid == pid)
+ {
+ /* erase pid */
+ DEBUG(5,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %.0f)\n",
+ (int)other_pid, (double)seek_back));
+ other_pid = (pid_t)0;
+ if(sys_lseek(smb_shm_processes_fd, seek_back, SEEK_CUR) == -1)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file sys_lseek failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+ if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file write failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ found = True;
+ break;
+ }
+ }
+ if (nb_read < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file read failed with code %s\n",strerror(errno)));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR smb_shm_unregister_process : couldn't find pid %d in file %s\n",
+ (int)pid,processreg_file));
+ close(smb_shm_processes_fd);
+ return False;
+ }
+
+
+ close(smb_shm_processes_fd);
+
+ return True;
+}
+
+
+static BOOL smb_shm_validate_header(int size)
+{
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_validate_header : shmem not mapped\n"));
+ return False;
+ }
+
+ if(smb_shm_header_p->smb_shm_magic != SMB_SHM_MAGIC)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : bad magic\n"));
+ return False;
+ }
+ if(smb_shm_header_p->smb_shm_version != SMB_SHM_VERSION)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : bad version %X\n",smb_shm_header_p->smb_shm_version));
+ return False;
+ }
+
+ if(smb_shm_header_p->total_size != size)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",smb_shm_header_p->total_size,size));
+ return False;
+ }
+
+ if(!smb_shm_header_p->consistent)
+ {
+ DEBUG(0,("ERROR smb_shm_validate_header : shmem not consistent\n"));
+ return False;
+ }
+ return True;
+}
+
+static BOOL smb_shm_initialize(int size)
+{
+ struct SmbShmBlockDesc * first_free_block_p;
+
+ DEBUG(5,("smb_shm_initialize : initializing shmem file of size %d\n",size));
+
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_initialize : shmem not mapped\n"));
+ return False;
+ }
+
+ smb_shm_header_p->smb_shm_magic = SMB_SHM_MAGIC;
+ smb_shm_header_p->smb_shm_version = SMB_SHM_VERSION;
+ smb_shm_header_p->total_size = size;
+ smb_shm_header_p->first_free_off = AlignedHeaderSize;
+ smb_shm_header_p->userdef_off = 0;
+
+ first_free_block_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
+ first_free_block_p->next = EOList_Off;
+ first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ;
+
+ smb_shm_header_p->statistics.cells_free = first_free_block_p->size;
+ smb_shm_header_p->statistics.cells_used = 0;
+ smb_shm_header_p->statistics.cells_system = 1;
+
+ smb_shm_header_p->consistent = True;
+
+ smb_shm_initialize_called = True;
+
+ return True;
+}
+
+static void smb_shm_solve_neighbors(struct SmbShmBlockDesc *head_p )
+{
+ struct SmbShmBlockDesc *next_p;
+
+ /* Check if head_p and head_p->next are neighbors and if so join them */
+ if ( head_p == EOList_Addr ) return ;
+ if ( head_p->next == EOList_Off ) return ;
+
+ next_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(head_p->next);
+ if ( ( head_p + head_p->size + 1 ) == next_p)
+ {
+ head_p->size += next_p->size +1 ; /* adapt size */
+ head_p->next = next_p->next ; /* link out */
+
+ smb_shm_header_p->statistics.cells_free += 1;
+ smb_shm_header_p->statistics.cells_system -= 1;
+ }
+}
+
+
+
+static BOOL smb_shm_close( void )
+{
+
+ if(smb_shm_initialize_called == False)
+ return True;
+
+ DEBUG(5,("smb_shm_close\n"));
+ if(smb_shm_times_locked > 0)
+ DEBUG(0,("WARNING smb_shm_close : shmem was still locked %d times\n",smb_shm_times_locked));;
+ if ((smb_shm_header_p != NULL) &&
+ (munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0))
+ {
+ DEBUG(0,("ERROR smb_shm_close : munmap failed with code %s\n",strerror(errno)));
+ }
+
+ smb_shm_global_lock();
+ DEBUG(5,("calling smb_shm_unregister_process(%s, %d)\n",
+ smb_shm_processreg_name, (int)getpid()));
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+
+ close(smb_shm_fd);
+
+ smb_shm_fd = -1;
+ smb_shm_processreg_name[0] = '\0';
+
+ smb_shm_header_p = (struct SmbShmHeader *)0;
+ smb_shm_times_locked = 0;
+
+ return True;
+}
+
+
+static BOOL smb_shm_free(int offset)
+{
+ struct SmbShmBlockDesc *header_p ; /* pointer to header of block to free */
+ struct SmbShmBlockDesc *scanner_p ; /* used to scan the list */
+ struct SmbShmBlockDesc *prev_p ; /* holds previous in the list */
+
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
+ return False;
+ }
+
+ smb_shm_global_lock();
+
+ if( !smb_shm_header_p->consistent)
+ {
+ DEBUG(0,("ERROR smb_shm_free : shmem not consistent\n"));
+ smb_shm_global_unlock();
+ return False;
+ }
+
+ header_p = ( (struct SmbShmBlockDesc *)smb_shm_offset2addr(offset) - 1); /* make pointer to header of block */
+
+ if (header_p->next != SMB_SHM_NOT_FREE_OFF)
+ {
+ DEBUG(0,("ERROR smb_shm_free : bad offset (%d)\n",offset));
+ smb_shm_global_unlock();
+ return False;
+ }
+
+ /* find a place in the free_list to put the header in */
+
+ /* set scanner and previous pointer to start of list */
+ prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ while ( ( scanner_p != EOList_Addr) && (scanner_p < header_p) ) /* while we didn't scan past its position */
+ {
+ prev_p = scanner_p ;
+ scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
+ }
+
+ smb_shm_header_p->consistent = False;
+
+ DEBUG(6,("smb_shm_free : freeing %d bytes at offset %d\n",header_p->size*CellSize,offset));
+
+ /* zero the area being freed - this allows us to find bugs faster */
+ memset(smb_shm_offset2addr(offset), 0, header_p->size*CellSize);
+
+ if ( scanner_p == prev_p )
+ {
+ smb_shm_header_p->statistics.cells_free += header_p->size;
+ smb_shm_header_p->statistics.cells_used -= header_p->size;
+
+ /* we must free it at the beginning of the list */
+ smb_shm_header_p->first_free_off = smb_shm_addr2offset(header_p); /* set the free_list_pointer to this block_header */
+
+ /* scanner is the one that was first in the list */
+ header_p->next = smb_shm_addr2offset(scanner_p);
+ smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
+
+ smb_shm_header_p->consistent = True;
+ smb_shm_global_unlock();
+ return True;
+ }
+ else
+ {
+ smb_shm_header_p->statistics.cells_free += header_p->size;
+ smb_shm_header_p->statistics.cells_used -= header_p->size;
+
+ prev_p->next = smb_shm_addr2offset(header_p);
+ header_p->next = smb_shm_addr2offset(scanner_p);
+ smb_shm_solve_neighbors(header_p) ;
+ smb_shm_solve_neighbors(prev_p) ;
+
+ smb_shm_header_p->consistent = True;
+ smb_shm_global_unlock();
+ return True;
+ }
+}
+
+static int smb_shm_get_userdef_off(void)
+{
+ if (!smb_shm_header_p)
+ return 0;
+ else
+ return smb_shm_header_p->userdef_off;
+}
+
+/*******************************************************************
+ Lock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL smb_shm_lock_hash_entry( unsigned int entry)
+{
+ int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
+
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ if (read_only)
+ return True;
+
+ /* Do an exclusive wait lock on the 4 byte region mapping into this entry */
+ if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, start, sizeof(int), F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry));
+ return True;
+}
+
+/*******************************************************************
+ Unlock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL smb_shm_unlock_hash_entry( unsigned int entry )
+{
+ int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
+
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_unlock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ return False;
+ }
+
+ if (read_only)
+ return True;
+
+ /* Do a wait lock on the 4 byte region mapping into this entry */
+ if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, start, sizeof(int), F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
+ return False;
+ }
+
+ DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry));
+ return True;
+}
+
+/*******************************************************************
+ Gather statistics on shared memory usage.
+ ******************************************************************/
+static BOOL smb_shm_get_usage(int *bytes_free,
+ int *bytes_used,
+ int *bytes_overhead)
+{
+ if( !smb_shm_header_p )
+ {
+ /* not mapped yet */
+ DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
+ return False;
+ }
+ *bytes_free = smb_shm_header_p->statistics.cells_free * CellSize;
+ *bytes_used = smb_shm_header_p->statistics.cells_used * CellSize;
+ *bytes_overhead = smb_shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize;
+
+ return True;
+}
+
+/*******************************************************************
+hash a number into a hash_entry
+ ******************************************************************/
+static unsigned smb_shm_hash_size(void)
+{
+ return SHMEM_HASH_SIZE;
+}
+
+static struct shmem_ops shmops = {
+ smb_shm_close,
+ smb_shm_alloc,
+ smb_shm_free,
+ smb_shm_get_userdef_off,
+ smb_shm_offset2addr,
+ smb_shm_addr2offset,
+ smb_shm_lock_hash_entry,
+ smb_shm_unlock_hash_entry,
+ smb_shm_get_usage,
+ smb_shm_hash_size,
+};
+
+/*******************************************************************
+ open the shared memory
+ ******************************************************************/
+struct shmem_ops *smb_shm_open(int ronly)
+{
+ pstring file_name;
+ SMB_OFF_T filesize;
+ BOOL created_new = False;
+ BOOL other_processes = True;
+ SMB_OFF_T size = (SMB_OFF_T)lp_shmem_size();
+
+ read_only = ronly;
+
+ pstrcpy(file_name,lp_lockdir());
+ if (!directory_exist(file_name,NULL)) {
+ if (read_only) return NULL;
+ mkdir(file_name,0755);
+ }
+ trim_string(file_name,"","/");
+ if (!*file_name) return(False);
+ pstrcat(file_name, "/SHARE_MEM_FILE");
+
+ DEBUG(5,("smb_shm_open : using shmem file %s to be of size %.0f\n",file_name,(double)size));
+
+ smb_shm_fd = open(file_name, read_only?O_RDONLY:(O_RDWR|O_CREAT),
+ SHM_FILE_MODE);
+
+ if ( smb_shm_fd < 0 )
+ {
+ DEBUG(0,("ERROR smb_shm_open : open failed with code %s\n",strerror(errno)));
+ return NULL;
+ }
+
+ if (!smb_shm_global_lock())
+ {
+ DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
+ return NULL;
+ }
+
+ if( (filesize = sys_lseek(smb_shm_fd, 0, SEEK_END)) < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_open : lseek failed with code %s\n",strerror(errno)));
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ /* return the file offset to 0 to save on later seeks */
+ sys_lseek(smb_shm_fd,0,SEEK_SET);
+
+ if (filesize == 0)
+ {
+ /* we just created a new one */
+ created_new = True;
+ }
+
+ /* to find out if some other process is already mapping the file,
+ we use a registration file containing the processids of the file mapping processes
+ */
+
+ /* construct processreg file name */
+ pstrcpy(smb_shm_processreg_name, file_name);
+ pstrcat(smb_shm_processreg_name, ".processes");
+
+ if (!read_only &&
+ !smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes))
+ {
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ if (!read_only && (created_new || !other_processes))
+ {
+ /* we just created a new one, or are the first opener, lets set it size */
+ if( sys_ftruncate(smb_shm_fd, size) <0)
+ {
+ DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %s\n",strerror(errno)));
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ /* paranoia */
+ sys_lseek(smb_shm_fd,0,SEEK_SET);
+
+ filesize = size;
+ }
+
+ if (size != filesize )
+ {
+ /* the existing file has a different size and we are not the first opener.
+ Since another process is still using it, we will use the file size */
+ DEBUG(0,("WARNING smb_shm_open : filesize (%.0f) != expected size (%.0f), using filesize\n",
+ (double)filesize, (double)size));
+
+ size = filesize;
+ }
+
+ smb_shm_header_p = (struct SmbShmHeader *)mmap(NULL, size,
+ read_only?PROT_READ:
+ (PROT_READ | PROT_WRITE),
+ MAP_FILE | MAP_SHARED,
+ smb_shm_fd, 0);
+ /* WARNING, smb_shm_header_p can be different for different processes mapping the same file ! */
+ if (smb_shm_header_p == (struct SmbShmHeader *)(-1))
+ {
+ DEBUG(0,("ERROR smb_shm_open : mmap failed with code %s\n",strerror(errno)));
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+
+ if (!read_only && (created_new || !other_processes))
+ {
+ smb_shm_initialize(size);
+ /* Create the hash buckets for the share file entries. */
+ smb_shm_create_hash_table(SHMEM_HASH_SIZE);
+ }
+ else if (!smb_shm_validate_header(size) )
+ {
+ /* existing file is corrupt, samba admin should remove it by hand */
+ DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n"));
+ munmap((caddr_t)smb_shm_header_p, size);
+ smb_shm_unregister_process(smb_shm_processreg_name, getpid());
+ smb_shm_global_unlock();
+ close(smb_shm_fd);
+ return NULL;
+ }
+
+ smb_shm_global_unlock();
+ return &shmops;
+}
+
+
+#else /* HAVE_SHARED_MMAP */
+ int shmem_dummy_procedure(void)
+{return 0;}
+#endif /* HAVE_SHARED_MMAP */
diff --git a/source/locking/shmem_sysv.c b/source/locking/shmem_sysv.c
new file mode 100644
index 00000000000..1dd4743df0a
--- /dev/null
+++ b/source/locking/shmem_sysv.c
@@ -0,0 +1,720 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Shared memory functions - SYSV IPC implementation
+ 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"
+
+
+#ifdef HAVE_SYSV_IPC
+
+extern int DEBUGLEVEL;
+
+#define SHMEM_KEY ((key_t)0x280267)
+#define SEMAPHORE_KEY (SHMEM_KEY+2)
+
+#define SHM_MAGIC 0x53484100
+#define SHM_VERSION 2
+
+#ifdef SHM_R
+#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
+#else
+#define IPC_PERMS 0644
+#endif
+
+
+#ifdef SECURE_SEMAPHORES
+/* secure semaphores are slow because we have to do a become_root()
+ on every call! */
+#define SEMAPHORE_PERMS IPC_PERMS
+#else
+#define SEMAPHORE_PERMS 0666
+#endif
+
+#define SHMEM_HASH_SIZE 13
+
+#define MIN_SHM_SIZE 0x1000
+
+static int shm_id;
+static int sem_id;
+static int shm_size;
+static int hash_size;
+static int global_lock_count;
+
+struct ShmHeader {
+ int shm_magic;
+ int shm_version;
+ int total_size; /* in bytes */
+ BOOL consistent;
+ int first_free_off;
+ int userdef_off; /* a userdefined offset. can be used to store
+ root of tree or list */
+ struct { /* a cell is a range of bytes of sizeof(struct
+ ShmBlockDesc) size */
+ int cells_free;
+ int cells_used;
+ int cells_system; /* number of cells used as allocated
+ block descriptors */
+ } statistics;
+};
+
+#define SHM_NOT_FREE_OFF (-1)
+struct ShmBlockDesc
+{
+ int next; /* offset of next block in the free list or
+ SHM_NOT_FREE_OFF when block in use */
+ int size; /* user size in BlockDescSize units */
+};
+
+#define EOList_Addr NULL
+#define EOList_Off (0)
+
+#define CellSize sizeof(struct ShmBlockDesc)
+
+/* HeaderSize aligned on a 8 byte boundary */
+#define AlignedHeaderSize ((sizeof(struct ShmHeader)+7) & ~7)
+
+static struct ShmHeader *shm_header_p = NULL;
+
+static int read_only;
+
+static BOOL sem_change(int i, int op)
+{
+#ifdef SECURE_SEMAPHORES
+ extern struct current_user current_user;
+ int became_root=0;
+#endif
+ struct sembuf sb;
+ int ret;
+
+ if (read_only) return True;
+
+#ifdef SECURE_SEMAPHORES
+ if (current_user.uid != 0) {
+ become_root(0);
+ became_root = 1;
+ }
+#endif
+
+ sb.sem_num = i;
+ sb.sem_op = op;
+ sb.sem_flg = 0;
+
+ ret = semop(sem_id, &sb, 1);
+
+ if (ret != 0) {
+ DEBUG(0,("ERROR: sem_change(%d,%d) failed (%s)\n",
+ i, op, strerror(errno)));
+ }
+
+#ifdef SECURE_SEMAPHORES
+ if (became_root) {
+ unbecome_root(0);
+ }
+#endif
+
+ return ret == 0;
+}
+
+static BOOL global_lock(void)
+{
+ global_lock_count++;
+ if (global_lock_count == 1)
+ return sem_change(0, -1);
+ return True;
+}
+
+static BOOL global_unlock(void)
+{
+ global_lock_count--;
+ if (global_lock_count == 0)
+ return sem_change(0, 1);
+ return True;
+}
+
+static void *shm_offset2addr(int offset)
+{
+ if (offset == 0 )
+ return (void *)(0);
+
+ if (!shm_header_p)
+ return (void *)(0);
+
+ return (void *)((char *)shm_header_p + offset);
+}
+
+static int shm_addr2offset(void *addr)
+{
+ if (!addr)
+ return 0;
+
+ if (!shm_header_p)
+ return 0;
+
+ return (int)((char *)addr - (char *)shm_header_p);
+}
+
+
+static int shm_alloc(int size)
+{
+ unsigned num_cells ;
+ struct ShmBlockDesc *scanner_p;
+ struct ShmBlockDesc *prev_p;
+ struct ShmBlockDesc *new_p;
+ int result_offset;
+
+
+ if (!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_alloc : shmem not mapped\n"));
+ return 0;
+ }
+
+ global_lock();
+
+ if (!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shm_alloc : shmem not consistent\n"));
+ global_unlock();
+ return 0;
+ }
+
+ /* calculate the number of cells */
+ num_cells = (size + (CellSize-1)) / CellSize;
+
+ /* set start of scan */
+ prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ /* scan the free list to find a matching free space */
+ while ((scanner_p != EOList_Addr) && (scanner_p->size < num_cells)) {
+ prev_p = scanner_p;
+ scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next);
+ }
+
+ /* at this point scanner point to a block header or to the end of
+ the list */
+ if (scanner_p == EOList_Addr) {
+ DEBUG(0,("ERROR shm_alloc : alloc of %d bytes failed\n",size));
+ global_unlock();
+ return (0);
+ }
+
+ /* going to modify shared mem */
+ shm_header_p->consistent = False;
+
+ /* if we found a good one : scanner == the good one */
+ if (scanner_p->size > num_cells + 2) {
+ /* Make a new one */
+ new_p = scanner_p + 1 + num_cells;
+ new_p->size = scanner_p->size - (num_cells + 1);
+ new_p->next = scanner_p->next;
+ scanner_p->size = num_cells;
+ scanner_p->next = shm_addr2offset(new_p);
+
+ shm_header_p->statistics.cells_free -= 1;
+ shm_header_p->statistics.cells_system += 1;
+ }
+
+ /* take it from the free list */
+ if (prev_p == scanner_p) {
+ shm_header_p->first_free_off = scanner_p->next;
+ } else {
+ prev_p->next = scanner_p->next;
+ }
+ shm_header_p->statistics.cells_free -= scanner_p->size;
+ shm_header_p->statistics.cells_used += scanner_p->size;
+
+ result_offset = shm_addr2offset(&(scanner_p[1]));
+ scanner_p->next = SHM_NOT_FREE_OFF;
+
+ /* end modification of shared mem */
+ shm_header_p->consistent = True;
+
+ global_unlock();
+
+ DEBUG(6,("shm_alloc : allocated %d bytes at offset %d\n",
+ size,result_offset));
+
+ return result_offset;
+}
+
+static void shm_solve_neighbors(struct ShmBlockDesc *head_p )
+{
+ struct ShmBlockDesc *next_p;
+
+ /* Check if head_p and head_p->next are neighbors and if so
+ join them */
+ if ( head_p == EOList_Addr ) return ;
+ if ( head_p->next == EOList_Off ) return ;
+
+ next_p = (struct ShmBlockDesc *)shm_offset2addr(head_p->next);
+ if ((head_p + head_p->size + 1) == next_p) {
+ head_p->size += next_p->size + 1; /* adapt size */
+ head_p->next = next_p->next; /* link out */
+
+ shm_header_p->statistics.cells_free += 1;
+ shm_header_p->statistics.cells_system -= 1;
+ }
+}
+
+
+static BOOL shm_free(int offset)
+{
+ struct ShmBlockDesc *header_p; /* pointer to header of
+ block to free */
+ struct ShmBlockDesc *scanner_p; /* used to scan the list */
+ struct ShmBlockDesc *prev_p; /* holds previous in the
+ list */
+
+ if (!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
+ return False;
+ }
+
+ global_lock();
+
+ if (!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shm_free : shmem not consistent\n"));
+ global_unlock();
+ return False;
+ }
+
+ /* make pointer to header of block */
+ header_p = ((struct ShmBlockDesc *)shm_offset2addr(offset) - 1);
+
+ if (header_p->next != SHM_NOT_FREE_OFF) {
+ DEBUG(0,("ERROR shm_free : bad offset (%d)\n",offset));
+ global_unlock();
+ return False;
+ }
+
+ /* find a place in the free_list to put the header in */
+
+ /* set scanner and previous pointer to start of list */
+ prev_p = (struct ShmBlockDesc *)
+ shm_offset2addr(shm_header_p->first_free_off);
+ scanner_p = prev_p ;
+
+ while ((scanner_p != EOList_Addr) &&
+ (scanner_p < header_p)) {
+ /* while we didn't scan past its position */
+ prev_p = scanner_p ;
+ scanner_p = (struct ShmBlockDesc *)
+ shm_offset2addr(scanner_p->next);
+ }
+
+ shm_header_p->consistent = False;
+
+ DEBUG(6,("shm_free : freeing %d bytes at offset %d\n",
+ header_p->size*CellSize,offset));
+
+ /* zero the area being freed - this allows us to find bugs faster */
+ memset(shm_offset2addr(offset), 0, header_p->size*CellSize);
+
+ if (scanner_p == prev_p) {
+ shm_header_p->statistics.cells_free += header_p->size;
+ shm_header_p->statistics.cells_used -= header_p->size;
+
+ /* we must free it at the beginning of the list */
+ shm_header_p->first_free_off = shm_addr2offset(header_p);
+ /* set the free_list_pointer to this block_header */
+
+ /* scanner is the one that was first in the list */
+ header_p->next = shm_addr2offset(scanner_p);
+ shm_solve_neighbors(header_p);
+
+ shm_header_p->consistent = True;
+ } else {
+ shm_header_p->statistics.cells_free += header_p->size;
+ shm_header_p->statistics.cells_used -= header_p->size;
+
+ prev_p->next = shm_addr2offset(header_p);
+ header_p->next = shm_addr2offset(scanner_p);
+ shm_solve_neighbors(header_p) ;
+ shm_solve_neighbors(prev_p) ;
+
+ shm_header_p->consistent = True;
+ }
+
+ global_unlock();
+ return True;
+}
+
+
+/*
+ * Function to create the hash table for the share mode entries. Called
+ * when smb shared memory is global locked.
+ */
+static BOOL shm_create_hash_table(unsigned int hash_entries)
+{
+ int size = hash_entries * sizeof(int);
+
+ global_lock();
+ shm_header_p->userdef_off = shm_alloc(size);
+
+ if(shm_header_p->userdef_off == 0) {
+ DEBUG(0,("shm_create_hash_table: Failed to create hash table of size %d\n",
+ size));
+ global_unlock();
+ return False;
+ }
+
+ /* Clear hash buckets. */
+ memset(shm_offset2addr(shm_header_p->userdef_off), '\0', size);
+ global_unlock();
+ return True;
+}
+
+
+static BOOL shm_validate_header(int size)
+{
+ if(!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_validate_header : shmem not mapped\n"));
+ return False;
+ }
+
+ if(shm_header_p->shm_magic != SHM_MAGIC) {
+ DEBUG(0,("ERROR shm_validate_header : bad magic\n"));
+ return False;
+ }
+
+ if(shm_header_p->shm_version != SHM_VERSION) {
+ DEBUG(0,("ERROR shm_validate_header : bad version %X\n",
+ shm_header_p->shm_version));
+ return False;
+ }
+
+ if(shm_header_p->total_size != size) {
+ DEBUG(0,("ERROR shmem size mismatch (old = %d, new = %d)\n",
+ shm_header_p->total_size,size));
+ return False;
+ }
+
+ if(!shm_header_p->consistent) {
+ DEBUG(0,("ERROR shmem not consistent\n"));
+ return False;
+ }
+ return True;
+}
+
+
+static BOOL shm_initialize(int size)
+{
+ struct ShmBlockDesc * first_free_block_p;
+
+ DEBUG(5,("shm_initialize : initializing shmem size %d\n",size));
+
+ if( !shm_header_p ) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_initialize : shmem not mapped\n"));
+ return False;
+ }
+
+ shm_header_p->shm_magic = SHM_MAGIC;
+ shm_header_p->shm_version = SHM_VERSION;
+ shm_header_p->total_size = size;
+ shm_header_p->first_free_off = AlignedHeaderSize;
+ shm_header_p->userdef_off = 0;
+
+ first_free_block_p = (struct ShmBlockDesc *)
+ shm_offset2addr(shm_header_p->first_free_off);
+ first_free_block_p->next = EOList_Off;
+ first_free_block_p->size =
+ (size - (AlignedHeaderSize+CellSize))/CellSize;
+ shm_header_p->statistics.cells_free = first_free_block_p->size;
+ shm_header_p->statistics.cells_used = 0;
+ shm_header_p->statistics.cells_system = 1;
+
+ shm_header_p->consistent = True;
+
+ return True;
+}
+
+static BOOL shm_close( void )
+{
+ return True;
+}
+
+
+static int shm_get_userdef_off(void)
+{
+ if (!shm_header_p)
+ return 0;
+ else
+ return shm_header_p->userdef_off;
+}
+
+
+/*******************************************************************
+ Lock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL shm_lock_hash_entry(unsigned int entry)
+{
+ return sem_change(entry+1, -1);
+}
+
+/*******************************************************************
+ Unlock a particular hash bucket entry.
+ ******************************************************************/
+static BOOL shm_unlock_hash_entry(unsigned int entry)
+{
+ return sem_change(entry+1, 1);
+}
+
+
+/*******************************************************************
+ Gather statistics on shared memory usage.
+ ******************************************************************/
+static BOOL shm_get_usage(int *bytes_free,
+ int *bytes_used,
+ int *bytes_overhead)
+{
+ if(!shm_header_p) {
+ /* not mapped yet */
+ DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
+ return False;
+ }
+
+ *bytes_free = shm_header_p->statistics.cells_free * CellSize;
+ *bytes_used = shm_header_p->statistics.cells_used * CellSize;
+ *bytes_overhead = shm_header_p->statistics.cells_system * CellSize +
+ AlignedHeaderSize;
+
+ return True;
+}
+
+
+/*******************************************************************
+hash a number into a hash_entry
+ ******************************************************************/
+static unsigned shm_hash_size(void)
+{
+ return hash_size;
+}
+
+
+static struct shmem_ops shmops = {
+ shm_close,
+ shm_alloc,
+ shm_free,
+ shm_get_userdef_off,
+ shm_offset2addr,
+ shm_addr2offset,
+ shm_lock_hash_entry,
+ shm_unlock_hash_entry,
+ shm_get_usage,
+ shm_hash_size,
+};
+
+/*******************************************************************
+ open the shared memory
+ ******************************************************************/
+struct shmem_ops *sysv_shm_open(int ronly)
+{
+ BOOL other_processes;
+ struct shmid_ds shm_ds;
+ struct semid_ds sem_ds;
+ union semun su;
+ int i;
+ int pid;
+
+ read_only = ronly;
+
+ shm_size = lp_shmem_size();
+
+ DEBUG(4,("Trying sysv shmem open of size %d\n", shm_size));
+
+ /* first the semaphore */
+ sem_id = semget(SEMAPHORE_KEY, 0, 0);
+ if (sem_id == -1) {
+ if (read_only) return NULL;
+
+ hash_size = SHMEM_HASH_SIZE;
+
+ while (hash_size > 1) {
+ sem_id = semget(SEMAPHORE_KEY, hash_size+1,
+ IPC_CREAT|IPC_EXCL| SEMAPHORE_PERMS);
+ if (sem_id != -1 ||
+ (errno != EINVAL && errno != ENOSPC)) break;
+ hash_size -= 5;
+ }
+
+ if (sem_id == -1) {
+ DEBUG(0,("Can't create or use semaphore [1]. Error was %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+
+ if (sem_id != -1) {
+ su.val = 1;
+ for (i=0;i<hash_size+1;i++) {
+ if (semctl(sem_id, i, SETVAL, su) != 0) {
+ DEBUG(1,("Failed to init semaphore %d. Error was %s\n",
+ i, strerror(errno)));
+ return NULL;
+ }
+ }
+ }
+ }
+ if (shm_id == -1) {
+ sem_id = semget(SEMAPHORE_KEY, 0, 0);
+ }
+ if (sem_id == -1) {
+ DEBUG(0,("Can't create or use semaphore [2]. Error was %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+
+ su.buf = &sem_ds;
+ if (semctl(sem_id, 0, IPC_STAT, su) != 0) {
+ DEBUG(0,("ERROR semctl: can't IPC_STAT. Error was %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+ hash_size = sem_ds.sem_nsems-1;
+
+ if (!read_only) {
+ if (sem_ds.sem_perm.cuid != 0 || sem_ds.sem_perm.cgid != 0) {
+ DEBUG(0,("ERROR: root did not create the semaphore\n"));
+ return NULL;
+ }
+
+ if (semctl(sem_id, 0, GETVAL, su) == 0 &&
+ !process_exists((pid=semctl(sem_id, 0, GETPID, su)))) {
+ DEBUG(0,("WARNING: clearing global IPC lock set by dead process %d\n",
+ pid));
+ su.val = 1;
+ if (semctl(sem_id, 0, SETVAL, su) != 0) {
+ DEBUG(0,("ERROR: Failed to clear global lock. Error was %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+ }
+
+ sem_ds.sem_perm.mode = SEMAPHORE_PERMS;
+ if (semctl(sem_id, 0, IPC_SET, su) != 0) {
+ DEBUG(0,("ERROR shmctl : can't IPC_SET. Error was %s\n",
+ strerror(errno)));
+ return NULL;
+ }
+ }
+
+ if (!global_lock())
+ return NULL;
+
+
+ for (i=1;i<hash_size+1;i++) {
+ if (semctl(sem_id, i, GETVAL, su) == 0 &&
+ !process_exists((pid=semctl(sem_id, i, GETPID, su)))) {
+ DEBUG(1,("WARNING: clearing IPC lock %d set by dead process %d\n",
+ i, pid));
+ su.val = 1;
+ if (semctl(sem_id, i, SETVAL, su) != 0) {
+ DEBUG(0,("ERROR: Failed to clear IPC lock %d. Error was %s\n",
+ i, strerror(errno)));
+ global_unlock();
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ * Try to use an existing key. Note that
+ * in order to use an existing key successfully
+ * size must be zero else shmget returns EINVAL.
+ * Thanks to Veselin Terzic <vterzic@systems.DHL.COM>
+ * for pointing this out.
+ */
+
+ shm_id = shmget(SHMEM_KEY, 0, 0);
+
+ /* if that failed then create one */
+ if (shm_id == -1) {
+ if (read_only) return NULL;
+ while (shm_size > MIN_SHM_SIZE) {
+ shm_id = shmget(SHMEM_KEY, shm_size,
+ IPC_CREAT | IPC_EXCL | IPC_PERMS);
+ if (shm_id != -1 ||
+ (errno != EINVAL && errno != ENOSPC)) break;
+ shm_size *= 0.8;
+ }
+ }
+
+ if (shm_id == -1) {
+ DEBUG(0,("Can't create or use IPC area. Error was %s\n", strerror(errno)));
+ global_unlock();
+ return NULL;
+ }
+
+
+ shm_header_p = (struct ShmHeader *)shmat(shm_id, 0,
+ read_only?SHM_RDONLY:0);
+ if ((long)shm_header_p == -1) {
+ DEBUG(0,("Can't attach to IPC area. Error was %s\n", strerror(errno)));
+ global_unlock();
+ return NULL;
+ }
+
+ /* to find out if some other process is already mapping the file,
+ we use a registration file containing the processids of the file
+ mapping processes */
+ if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
+ DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n", strerror(errno)));
+ global_unlock();
+ return NULL;
+ }
+
+ if (!read_only) {
+ if (shm_ds.shm_perm.cuid != 0 || shm_ds.shm_perm.cgid != 0) {
+ DEBUG(0,("ERROR: root did not create the shmem\n"));
+ global_unlock();
+ return NULL;
+ }
+ }
+
+ shm_size = shm_ds.shm_segsz;
+
+ other_processes = (shm_ds.shm_nattch > 1);
+
+ if (!read_only && !other_processes) {
+ memset((char *)shm_header_p, 0, shm_size);
+ shm_initialize(shm_size);
+ shm_create_hash_table(hash_size);
+ DEBUG(3,("Initialised IPC area of size %d\n", shm_size));
+ } else if (!shm_validate_header(shm_size)) {
+ /* existing file is corrupt, samba admin should remove
+ it by hand */
+ DEBUG(0,("ERROR shm_open : corrupt IPC area - remove it!\n"));
+ global_unlock();
+ return NULL;
+ }
+
+ global_unlock();
+ return &shmops;
+}
+
+
+
+#else
+ int ipc_dummy_procedure(void)
+{return 0;}
+#endif
diff --git a/source/lsarpcd/srv_lsa.c b/source/lsarpcd/srv_lsa.c
new file mode 100644
index 00000000000..35ceeace04f
--- /dev/null
+++ b/source/lsarpcd/srv_lsa.c
@@ -0,0 +1,497 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern DOM_SID global_machine_sid;
+
+/***************************************************************************
+lsa_reply_open_policy
+ ***************************************************************************/
+static void lsa_reply_open_policy(prs_struct *rdata)
+{
+ int i;
+ LSA_R_OPEN_POL r_o;
+
+ ZERO_STRUCT(r_o);
+
+ /* set up the LSA QUERY INFO response */
+
+ for (i = 4; i < POL_HND_SIZE; i++)
+ {
+ r_o.pol.data[i] = i;
+ }
+ r_o.status = 0x0;
+
+ /* store the response in the SMB stream */
+ lsa_io_r_open_pol("", &r_o, rdata, 0);
+}
+
+/***************************************************************************
+make_dom_query
+ ***************************************************************************/
+static void make_dom_query(DOM_QUERY *d_q, char *dom_name, DOM_SID *dom_sid)
+{
+ int domlen = strlen(dom_name);
+
+ d_q->uni_dom_max_len = domlen * 2;
+ d_q->uni_dom_str_len = domlen * 2;
+
+ d_q->buffer_dom_name = 4; /* domain buffer pointer */
+ d_q->buffer_dom_sid = 2; /* domain sid pointer */
+
+ /* this string is supposed to be character short */
+ make_unistr2(&(d_q->uni_domain_name), dom_name, domlen);
+
+ make_dom_sid2(&(d_q->dom_sid), dom_sid);
+}
+
+/***************************************************************************
+lsa_reply_query_info
+ ***************************************************************************/
+static void lsa_reply_enum_trust_dom(LSA_Q_ENUM_TRUST_DOM *q_e,
+ prs_struct *rdata,
+ uint32 enum_context, char *dom_name, DOM_SID *dom_sid)
+{
+ LSA_R_ENUM_TRUST_DOM r_e;
+
+ ZERO_STRUCT(r_e);
+
+ /* set up the LSA QUERY INFO response */
+ make_r_enum_trust_dom(&r_e, enum_context, dom_name, dom_sid,
+ dom_name != NULL ? 0x0 : 0x80000000 | NT_STATUS_UNABLE_TO_FREE_VM);
+
+ /* store the response in the SMB stream */
+ lsa_io_r_enum_trust_dom("", &r_e, rdata, 0);
+}
+
+/***************************************************************************
+lsa_reply_query_info
+ ***************************************************************************/
+static void lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, prs_struct *rdata,
+ char *dom_name, DOM_SID *dom_sid)
+{
+ LSA_R_QUERY_INFO r_q;
+
+ ZERO_STRUCT(r_q);
+
+ /* set up the LSA QUERY INFO response */
+
+ r_q.undoc_buffer = 0x22000000; /* bizarre */
+ r_q.info_class = q_q->info_class;
+
+ make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
+
+ r_q.status = 0x0;
+
+ /* store the response in the SMB stream */
+ lsa_io_r_query("", &r_q, rdata, 0);
+}
+
+/***************************************************************************
+make_dom_ref
+
+ pretty much hard-coded choice of "other" sids, unfortunately...
+
+ ***************************************************************************/
+static void make_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ int len_dom_name = strlen(dom_name);
+
+ ref->undoc_buffer = 1;
+ ref->num_ref_doms_1 = 4;
+ ref->buffer_dom_name = 1;
+ ref->max_entries = 32;
+ ref->num_ref_doms_2 = 4;
+
+ make_uni_hdr2(&(ref->hdr_dom_name ), len_dom_name , len_dom_name , 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[0]), sizeof(DOM_SID), sizeof(DOM_SID), 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[1]), sizeof(DOM_SID), sizeof(DOM_SID), 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[2]), sizeof(DOM_SID), sizeof(DOM_SID), 0);
+
+ if (dom_name != NULL)
+ {
+ make_unistr(&(ref->uni_dom_name), dom_name);
+ }
+
+ make_dom_sid2(&(ref->ref_dom[0]), dom_sid );
+ make_dom_sid2(&(ref->ref_dom[1]), other_sid1);
+ make_dom_sid2(&(ref->ref_dom[2]), other_sid2);
+ make_dom_sid2(&(ref->ref_dom[3]), other_sid3);
+}
+
+/***************************************************************************
+make_reply_lookup_rids
+ ***************************************************************************/
+static void make_reply_lookup_rids(LSA_R_LOOKUP_RIDS *r_l,
+ int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
+ char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ int i;
+
+ make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
+ other_sid1, other_sid2, other_sid3);
+
+ r_l->num_entries = num_entries;
+ r_l->undoc_buffer = 1;
+ r_l->num_entries2 = num_entries;
+
+ SMB_ASSERT_ARRAY(r_l->dom_rid, num_entries);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ make_dom_rid2(&(r_l->dom_rid[i]), dom_rids[i]);
+ }
+
+ r_l->num_entries3 = num_entries;
+}
+
+/***************************************************************************
+make_lsa_trans_names
+ ***************************************************************************/
+static void make_lsa_trans_names(LSA_TRANS_NAME_ENUM *trn,
+ int num_entries, DOM_SID2 sid[MAX_LOOKUP_SIDS],
+ uint32 *total)
+{
+ uint32 status = 0x0;
+ int i;
+ (*total) = 0;
+
+ SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ uint32 rid = 0xffffffff;
+ uint8 num_auths = sid[i].sid.num_auths;
+ fstring name;
+ uint32 type;
+
+ trn->ptr_name[i] = 0;
+ trn->ptr_name[(*total)] = 0;
+
+ SMB_ASSERT_ARRAY(sid[i].sid.sub_auths, num_auths);
+
+ /* find the rid to look up */
+ if (num_auths != 0)
+ {
+ rid = sid[i].sid.sub_auths[num_auths-1];
+
+ status = 0xC0000000 | NT_STATUS_NONE_MAPPED;
+
+ status = (status != 0x0) ? lookup_user_name (rid, name, &type) : status;
+ status = (status != 0x0) ? lookup_group_name(rid, name, &type) : status;
+ status = (status != 0x0) ? lookup_alias_name(rid, name, &type) : status;
+ }
+
+ if (status == 0x0)
+ {
+ trn->ptr_name[i] = 1;
+ make_lsa_trans_name(&(trn->name[(*total)]), type, name, (*total));
+ (*total)++;
+ }
+ }
+
+ trn->num_entries = (*total);
+ trn->ptr_trans_names = 1;
+ trn->num_entries2 = (*total);
+}
+
+/***************************************************************************
+make_reply_lookup_sids
+ ***************************************************************************/
+static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
+ DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *names,
+ uint32 mapped_count, uint32 status)
+{
+ r_l->dom_ref = ref;
+ r_l->names = names;
+ r_l->mapped_count = mapped_count;
+ r_l->status = status;
+}
+
+/***************************************************************************
+lsa_reply_lookup_sids
+ ***************************************************************************/
+static void lsa_reply_lookup_sids(prs_struct *rdata,
+ int num_entries, DOM_SID2 sid[MAX_LOOKUP_SIDS],
+ char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ LSA_R_LOOKUP_SIDS r_l;
+ DOM_R_REF ref;
+ LSA_TRANS_NAME_ENUM names;
+ uint32 mapped_count = 0;
+
+ ZERO_STRUCT(r_l);
+ ZERO_STRUCT(ref);
+ ZERO_STRUCT(names);
+
+ /* set up the LSA Lookup SIDs response */
+ make_dom_ref(&ref, dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
+ make_lsa_trans_names(&names, num_entries, sid, &mapped_count);
+ make_reply_lookup_sids(&r_l, &ref, &names, mapped_count, 0x0);
+
+ /* store the response in the SMB stream */
+ lsa_io_r_lookup_sids("", &r_l, rdata, 0);
+}
+
+/***************************************************************************
+lsa_reply_lookup_rids
+ ***************************************************************************/
+static void lsa_reply_lookup_rids(prs_struct *rdata,
+ int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
+ char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ LSA_R_LOOKUP_RIDS r_l;
+
+ ZERO_STRUCT(r_l);
+
+ /* set up the LSA Lookup RIDs response */
+ make_reply_lookup_rids(&r_l, num_entries, dom_rids,
+ dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
+ r_l.status = 0x0;
+
+ /* store the response in the SMB stream */
+ lsa_io_r_lookup_rids("", &r_l, rdata, 0);
+}
+
+/***************************************************************************
+api_lsa_open_policy
+ ***************************************************************************/
+static void api_lsa_open_policy( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_OPEN_POL q_o;
+
+ ZERO_STRUCT(q_o);
+
+ /* grab the server, object attributes and desired access flag...*/
+ lsa_io_q_open_pol("", &q_o, data, 0);
+
+ /* lkclXXXX having decoded it, ignore all fields in the open policy! */
+
+ /* return a 20 byte policy handle */
+ lsa_reply_open_policy(rdata);
+}
+
+/***************************************************************************
+api_lsa_enum_trust_dom
+ ***************************************************************************/
+static void api_lsa_enum_trust_dom( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_ENUM_TRUST_DOM q_e;
+
+ ZERO_STRUCT(q_e);
+
+ /* grab the enum trust domain context etc. */
+ lsa_io_q_enum_trust_dom("", &q_e, data, 0);
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_enum_trust_dom(&q_e, rdata,
+ 0, NULL, NULL);
+}
+
+/***************************************************************************
+api_lsa_query_info
+ ***************************************************************************/
+static void api_lsa_query_info( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_QUERY_INFO q_i;
+ pstring dom_name;
+
+ ZERO_STRUCT(q_i);
+
+ /* grab the info class and policy handle */
+ lsa_io_q_query("", &q_i, data, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_query_info(&q_i, rdata, dom_name, &global_machine_sid);
+}
+
+/***************************************************************************
+api_lsa_lookup_sids
+ ***************************************************************************/
+static void api_lsa_lookup_sids( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_LOOKUP_SIDS q_l;
+ pstring dom_name;
+ DOM_SID sid_S_1_1;
+ DOM_SID sid_S_1_3;
+ DOM_SID sid_S_1_5;
+
+ ZERO_STRUCT(q_l);
+ ZERO_STRUCT(sid_S_1_1);
+ ZERO_STRUCT(sid_S_1_3);
+ ZERO_STRUCT(sid_S_1_5);
+
+ /* grab the info class and policy handle */
+ lsa_io_q_lookup_sids("", &q_l, data, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+
+ string_to_sid(&sid_S_1_1, "S-1-1");
+ string_to_sid(&sid_S_1_3, "S-1-3");
+ string_to_sid(&sid_S_1_5, "S-1-5");
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_lookup_sids(rdata,
+ q_l.sids.num_entries, q_l.sids.sid, /* SIDs */
+ dom_name, &global_machine_sid, /* domain name, domain SID */
+ &sid_S_1_1, &sid_S_1_3, &sid_S_1_5); /* the three other SIDs */
+}
+
+/***************************************************************************
+api_lsa_lookup_names
+ ***************************************************************************/
+static void api_lsa_lookup_names( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ int i;
+ LSA_Q_LOOKUP_RIDS q_l;
+ pstring dom_name;
+ DOM_SID sid_S_1_1;
+ DOM_SID sid_S_1_3;
+ DOM_SID sid_S_1_5;
+ uint32 dom_rids[MAX_LOOKUP_SIDS];
+ uint32 dummy_g_rid;
+
+ ZERO_STRUCT(q_l);
+ ZERO_STRUCT(sid_S_1_1);
+ ZERO_STRUCT(sid_S_1_3);
+ ZERO_STRUCT(sid_S_1_5);
+ ZERO_ARRAY(dom_rids);
+
+ /* grab the info class and policy handle */
+ lsa_io_q_lookup_rids("", &q_l, data, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+
+ string_to_sid(&sid_S_1_1, "S-1-1");
+ string_to_sid(&sid_S_1_3, "S-1-3");
+ string_to_sid(&sid_S_1_5, "S-1-5");
+
+ SMB_ASSERT_ARRAY(q_l.lookup_name, q_l.num_entries);
+
+ /* convert received RIDs to strings, so we can do them. */
+ for (i = 0; i < q_l.num_entries; i++)
+ {
+ fstring user_name;
+ fstrcpy(user_name, unistr2(q_l.lookup_name[i].str.buffer));
+ /*
+ * Map to the UNIX username.
+ */
+ map_username(user_name);
+
+ /*
+ * Do any case conversions.
+ */
+ (void)Get_Pwnam(user_name, True);
+
+ if (!pdb_name_to_rid(user_name, &dom_rids[i], &dummy_g_rid))
+ {
+ /* WHOOPS! we should really do something about this... */
+ dom_rids[i] = 0;
+ }
+ }
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_lookup_rids(rdata,
+ q_l.num_entries, dom_rids, /* text-converted SIDs */
+ dom_name, &global_machine_sid, /* domain name, domain SID */
+ &sid_S_1_1, &sid_S_1_3, &sid_S_1_5); /* the three other SIDs */
+}
+
+/***************************************************************************
+ api_lsa_close
+ ***************************************************************************/
+static void api_lsa_close( int uid, prs_struct *data,
+ prs_struct *rdata)
+{
+ /* XXXX this is NOT good */
+ char *q = mem_data(&(rdata->data), rdata->offset);
+
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+
+ rdata->offset += 24;
+}
+
+/***************************************************************************
+ api_lsa_open_secret
+ ***************************************************************************/
+static void api_lsa_open_secret( int uid, prs_struct *data,
+ prs_struct *rdata)
+{
+ /* XXXX this is NOT good */
+ char *q = mem_data(&(rdata->data), rdata->offset);
+
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND); q += 4;
+
+ rdata->offset += 24;
+}
+
+/***************************************************************************
+ \PIPE\ntlsa commands
+ ***************************************************************************/
+static struct api_struct api_lsa_cmds[] =
+{
+ { "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 },
+ { NULL , 0 , NULL }
+};
+
+/***************************************************************************
+ api_ntLsarpcTNP
+ ***************************************************************************/
+BOOL api_ntlsa_rpc(pipes_struct *p, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_ntlsa_rpc", api_lsa_cmds, data);
+}
+
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/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..3054ad7353b
--- /dev/null
+++ b/source/nmbd/asyncdns.c
@@ -0,0 +1,349 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/***************************************************************************
+ 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 int 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 = 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", 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", 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 - ", 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..bdafdd44fcd
--- /dev/null
+++ b/source/nmbd/nmbd.c
@@ -0,0 +1,771 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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"
+
+extern int DEBUGLEVEL;
+
+extern pstring debugf;
+pstring servicesf = CONFIGFILE;
+
+extern pstring scope;
+
+int ClientNMB = -1;
+int ClientDGRAM = -1;
+int global_nmb_port = -1;
+
+extern pstring myhostname;
+static pstring host_file;
+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;
+
+extern struct in_addr ipzero;
+
+/**************************************************************************** **
+ 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 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_services( True );
+
+ set_samba_nb_type();
+
+ 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, debugf );
+ 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
+
+
+/**************************************************************************** **
+ 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 services file
+ **************************************************************************** */
+BOOL reload_services(BOOL test)
+{
+ BOOL ret;
+ extern fstring remote_machine;
+
+ fstrcpy( remote_machine, "nmb" );
+
+ if ( lp_loaded() )
+ {
+ pstring fname;
+ pstrcpy( fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
+ {
+ pstrcpy(servicesf,fname);
+ test = False;
+ }
+ }
+
+ if ( test && !lp_file_list_changed() )
+ return(True);
+
+ ret = lp_load( servicesf, True , False, False);
+
+ /* perhaps the config filename is now set */
+ if ( !test )
+ {
+ DEBUG( 3, ( "services not loaded\n" ) );
+ reload_services( True );
+ }
+
+ /* Do a sanity check for a misconfigured nmbd */
+ if( lp_wins_support() && *lp_wins_server() )
+ {
+ DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
+cannot be set in the smb.conf file. nmbd aborting.\n"));
+ exit(10);
+ }
+
+ return(ret);
+} /* reload_services */
+
+/**************************************************************************** **
+ The main select loop.
+ **************************************************************************** */
+static void process(void)
+{
+ BOOL run_election;
+
+ while( True )
+ {
+ time_t t = time(NULL);
+
+ /*
+ * 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)
+ */
+ 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
+ */
+ sync_all_dmbs(t);
+ }
+} /* 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);
+ else
+ ClientNMB = 0;
+
+ ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0);
+
+ 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;
+ pstring nbname;
+
+ if (! *global_myname)
+ {
+ fstrcpy( global_myname, myhostname );
+ p = strchr( 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();
+ for( namecount=0; next_token(&ptr,nbname,NULL, sizeof(nbname)); namecount++ )
+ ;
+ 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();
+ while ( next_token( &ptr, nbname, NULL, sizeof(nbname) ) )
+ {
+ 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++] = strdup( nbname );
+ }
+
+ /* Check the strdups succeeded. */
+ for( n = 0; n < namecount; n++ )
+ if( NULL == my_netbios_names[n] )
+ {
+ DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
+ return False;
+ }
+
+ /* Terminate name list */
+ my_netbios_names[namecount++] = NULL;
+
+ fstrcpy( local_machine, global_myname );
+ trim_string( local_machine, " ", " " );
+ p = strchr( 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)
+{
+ DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
+
+ printf( "Usage: %s [-n name] [-D] [-p port] [-d debuglevel] ", pname );
+ printf( "[-l log basename]\n" );
+ 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. " );
+ printf( "the netbios name to advertise for this host\n");
+ printf( "\t-H hosts file load a netbios hosts file\n" );
+ printf( "\t-a append to log file (default)\n" );
+ printf( "\t-o overwrite log file, don't append\n" );
+ printf( "\n");
+} /* usage */
+
+
+/**************************************************************************** **
+ main program
+ **************************************************************************** */
+ int main(int argc,char *argv[])
+{
+ int opt;
+ extern FILE *dbf;
+ extern char *optarg;
+ extern BOOL append_log;
+
+ append_log = True; /* Default, override with '-o' option. */
+
+ global_nmb_port = NMB_PORT;
+ *host_file = 0;
+ global_in_nmbd = True;
+
+ StartupTime = time(NULL);
+
+ sys_srandom(time(NULL) ^ getpid());
+
+ TimeInit();
+
+ pstrcpy( debugf, NMBLOGFILE );
+
+ setup_logging( argv[0], False );
+
+ charset_initialise();
+
+ if(!initialize_password_db())
+ exit(1);
+
+#ifdef LMHOSTSFILE
+ pstrcpy( host_file, LMHOSTSFILE );
+#endif
+
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-'))
+ {
+ argv++;
+ argc--;
+ }
+
+ fault_setup((void (*)(void *))fault_continue );
+
+ CatchSignal( SIGHUP, SIGNAL_CAST sig_hup );
+ CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
+
+ /* Setup the signals that allow the debug log level
+ to by dynamically changed. */
+
+ /* If we are using the malloc debug code we can't use
+ SIGUSR1 and SIGUSR2 to do debug level changes. */
+#ifndef MEM_MAN
+#if defined(SIGUSR1)
+ CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
+
+#if defined(SIGUSR2)
+ CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+#endif /* MEM_MAN */
+
+ while( EOF !=
+ (opt = getopt( argc, argv, "aos:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:" )) )
+ {
+ switch (opt)
+ {
+ case 's':
+ pstrcpy(servicesf,optarg);
+ break;
+ case 'N':
+ case 'B':
+ case 'I':
+ case 'C':
+ case 'G':
+ DEBUG(0,("Obsolete option '%c' used\n",opt));
+ break;
+ case 'H':
+ pstrcpy(host_file,optarg);
+ break;
+ case 'n':
+ pstrcpy(global_myname,optarg);
+ strupper(global_myname);
+ break;
+ case 'l':
+ slprintf(debugf,sizeof(debugf)-1, "%s.nmb",optarg);
+ break;
+ case 'i':
+ pstrcpy(scope,optarg);
+ strupper(scope);
+ 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;
+ default:
+ if( !is_a_socket(0) )
+ {
+ usage(argv[0]);
+ exit(0);
+ }
+ break;
+ }
+ }
+
+ reopen_logs();
+
+ DEBUG( 1, ( "Netbios nameserver version %s started.\n", VERSION ) );
+ DEBUGADD( 1, ( "Copyright Andrew Tridgell 1994-1998\n" ) );
+
+ if( !get_myname( myhostname, NULL) )
+ {
+ DEBUG( 0, ( "Unable to get my hostname - exiting.\n" ) );
+ return -1;
+ }
+
+ if ( !reload_services(False) )
+ return(-1);
+
+ codepage_initialise(lp_client_code_page());
+
+ if(!init_structs())
+ return -1;
+
+ reload_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)
+ {
+ DEBUG( 2, ( "Becoming a daemon.\n" ) );
+ become_daemon();
+ }
+
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
+
+ pidfile_create("nmbd");
+
+ 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. */
+ if ( *host_file )
+ {
+ load_lmhosts_file(host_file);
+ DEBUG(3,("Loaded hosts file\n"));
+ }
+
+ /* 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 );
+#if defined(SIGUSR1)
+ BlockSignals( True, SIGUSR1);
+#endif /* SIGUSR1 */
+#if defined(SIGUSR2)
+ BlockSignals( True, SIGUSR2);
+#endif /* SIGUSR2 */
+
+ process();
+ close_sockets();
+
+ if (dbf)
+ 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..cfaec3378d2
--- /dev/null
+++ b/source/nmbd/nmbd_become_dmb.c
@@ -0,0 +1,394 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr ipzero;
+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, 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, scope);
+
+ 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);
+ }
+}
+
+/****************************************************************************
+ 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) || ip_equal(ipzero, 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 ", 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, 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,scope);
+
+ /*
+ * 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,scope);
+
+ /*
+ * 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), 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_domain_master())
+ {
+ 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..80609cf504a
--- /dev/null
+++ b/source/nmbd/nmbd_become_lmb.c
@@ -0,0 +1,610 @@
+/*
+ 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 DEBUGLEVEL;
+extern pstring scope;
+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, scope);
+
+ 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",
+ 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", 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, scope);
+ 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.",
+ 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.",
+ 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, scope);
+ 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", 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, 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..12ce00df4f2
--- /dev/null
+++ b/source/nmbd/nmbd_browserdb.c
@@ -0,0 +1,185 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* -------------------------------------------------------------------------- **
+ * 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 )
+ {
+ free( (char *)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 );
+ }
+
+ bzero( (char *)browc, 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..da514076e66
--- /dev/null
+++ b/source/nmbd/nmbd_browsesync.c
@@ -0,0 +1,617 @@
+/*
+ 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 DEBUGLEVEL;
+extern pstring scope;
+extern struct in_addr ipzero;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/* This is our local master browser list database. */
+extern struct 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))) {
+ DEBUG(0, ("sync_with_lmb: failed to get a \
+workgroup for a local master browser cache entry workgroup %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))
+ {
+ DEBUG(0,("sync_with_lmb: We are trying to sync with a local master browser %s \
+for workgroup %s and we are not a domain master browser on this workgroup. Error !\n",
+ browc->lmb_name, browc->work_group));
+ return;
+ }
+
+ DEBUG(2, ("sync_with_lmb: Initiating sync with local master browser %s<0x20> at IP %s for \
+workgroup %s\n", browc->lmb_name, inet_ntoa(browc->ip), 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))
+ {
+ DEBUG(2,("announce_local_master_browser_to_domain_master_browser: We are both a domain \
+and a local master browser for workgroup %s. \
+Do not announce to ourselves.\n", work->work_group ));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_MasterAnnouncement;
+ p++;
+
+ StrnCpy(p,global_myname,15);
+ strupper(p);
+ p = skip_string(p,1);
+
+ DEBUG(4,("announce_local_master_browser_to_domain_master_browser: Sending local master announce \
+to %s for workgroup %s.\n", 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)
+{
+ DEBUG(2, ("sync_with_dmb: Initiating sync with domain master browser %s at IP %s for \
+workgroup %s\n", namestr(&work->dmb_name), inet_ntoa(work->dmb_addr), 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)
+ {
+ DEBUG(0,("domain_master_node_status_success: Unable to find workgroup %s on subnet %s.\n",
+ userdata->data, subrec->subnet_name));
+ return;
+ }
+
+ DEBUG(3,("domain_master_node_status_success: Success in node status for workgroup %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, scope);
+
+ /* 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
+ DEBUG(0,("domain_master_node_status_success: Failed to find a SERVER<0x20> \
+name in reply from IP %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;
+
+ DEBUG(0,("domain_master_node_status_fail: Doing a node status request to \
+the domain master browser for workgroup %s at IP %s failed. Cannot sync browser \
+lists.\n", userdata->data, inet_ntoa(rrec->packet->ip) ));
+
+}
+
+/****************************************************************************
+ 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))) {
+ DEBUG(0, ("find_domain_master_name_query_success: failed to find \
+workgroup %s\n", q_name->name ));
+ return;
+ }
+
+ /* First check if we already have a dmb for this workgroup. */
+
+ if(!ip_equal(work->dmb_addr, ipzero) && 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
+ putip((char *)&work->dmb_addr, &ipzero);
+
+ /* Now initiate the node status request. */
+ bzero((char *)&nmbname, sizeof(nmbname));
+ nmbname.name[0] = '*';
+
+ /* 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)
+{
+ DEBUG(0,("find_domain_master_name_query_fail: Unable to find the Domain Master \
+Browser name %s for the workgroup %s. Unable to sync browse lists in this workgroup.\n",
+ namestr(question_name), question_name->name ));
+}
+
+/****************************************************************************
+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)
+ {
+ DEBUG(10,("announce_and_sync_with_domain_master_browser: Ignoring as we are not a WINS client.\n"));
+ return;
+ }
+
+ make_nmb_name(&nmbname,work->work_group,0x1b,scope);
+
+ /* 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;
+
+ DEBUG(3,("get_domain_master_name_node_status_success: 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))
+ {
+
+ DEBUG(5,("get_domain_master_name_node_status_success: %s(%s) is a domain \
+master browser for workgroup %s. Adding this name.\n",
+ server_name, inet_ntoa(from_ip), 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, scope);
+ work->dmb_name = nmbname;
+ work->dmb_addr = from_ip;
+ }
+ break;
+ }
+ }
+ }
+ else
+ DEBUG(0,("get_domain_master_name_node_status_success: Failed to find a WORKGROUP<0x1b> \
+name in reply from IP %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)
+{
+ DEBUG(0,("get_domain_master_name_node_status_fail: Doing a node status request to \
+the domain master browser at IP %s failed. Cannot get workgroup name.\n",
+ inet_ntoa(rrec->packet->ip) ));
+
+}
+/****************************************************************************
+ 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;
+
+ DEBUG(5,("find_all_domain_master_names_query_succes: Got answer from WINS server of %d \
+IP addresses for Domain Master Browsers.\n", rrec->rdlength / 6 ));
+
+ for(i = 0; i < rrec->rdlength / 6; i++)
+ {
+ /* Initiate the node status requests. */
+ bzero((char *)&nmbname, sizeof(nmbname));
+ nmbname.name[0] = '*';
+
+ putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
+
+ /*
+ * Don't send node status requests to ourself.
+ */
+
+ if(ismyip( send_ip ))
+ {
+ DEBUG(5,("find_all_domain_master_names_query_succes: Not sending node status \
+to our own IP %s.\n", inet_ntoa(send_ip) ));
+ continue;
+ }
+
+ DEBUG(5,("find_all_domain_master_names_query_succes: 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)
+{
+ DEBUG(10,("find_domain_master_name_query_fail: WINS server did not reply to a query \
+for name %s. This means it is probably not a Samba 1.9.18 or above WINS server.\n",
+ namestr(question_name) ));
+}
+
+/****************************************************************************
+ 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)
+ {
+ DEBUG(0,("collect_all_workgroup_names_from_wins_server: Cannot find my workgroup %s on subnet %s.\n",
+ global_myworkgroup, 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,scope);
+
+ /* 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, scope);
+ }
+
+ 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..cd310639e94
--- /dev/null
+++ b/source/nmbd/nmbd_elections.c
@@ -0,0 +1,385 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+
+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 ));
+
+ bzero(outbuf,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;
+
+ 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, scope);
+ 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", 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);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************
+ 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;
+
+ 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 ));
+ return;
+ }
+
+ 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 ));
+ return;
+ }
+
+ 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);
+ }
+ }
+}
+
+/****************************************************************************
+ 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, scope);
+ 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", 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;
+}
diff --git a/source/nmbd/nmbd_incomingdgrams.c b/source/nmbd/nmbd_incomingdgrams.c
new file mode 100644
index 00000000000..e6c4ab27718
--- /dev/null
+++ b/source/nmbd/nmbd_incomingdgrams.c
@@ -0,0 +1,816 @@
+/*
+ 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 DEBUGLEVEL;
+
+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;
+
+ 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),
+ 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)
+ return;
+ }
+
+ 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;
+}
+
+/*******************************************************************
+ 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;
+
+ 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),
+ 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), namestr(&dgram->dest_name)));
+ return;
+ }
+
+ 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)
+ return;
+ }
+ 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;
+}
+
+/*******************************************************************
+ 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;
+
+ 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),
+ 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));
+ return;
+ }
+
+ /* 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)
+ return;
+
+ /* We have no record of this workgroup. Add it. */
+ if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
+ return;
+ }
+
+ /* 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 */
+ return;
+ }
+
+ /* 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;
+}
+
+/*******************************************************************
+ 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;
+
+ 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"));
+ return;
+ }
+
+ 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));
+ return;
+ }
+
+ 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)));
+ return;
+ }
+
+ /* 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);
+}
+
+/*******************************************************************
+ 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;
+
+ 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),
+ 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. */
+ return;
+ }
+
+ /* 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)
+ return;
+ }
+
+ 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;
+}
+
+/****************************************************************************
+ 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;
+ int len;
+ struct server_record *servrec;
+
+ bzero(outbuf,sizeof(outbuf));
+
+ DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
+ work->work_group, 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. */
+ for (servrec = work->serverlist; servrec; servrec = servrec->next)
+ {
+ 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);
+ }
+
+ SCVAL(countptr, 0, count);
+
+ len = PTR_DIFF(p, outbuf);
+
+ 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;
+
+ DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
+ namestr(&dgram->source_name), inet_ntoa(p->ip),
+ 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));
+ return;
+ }
+
+ if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
+ {
+ DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
+subnet %s.\n", workgroup_name, subrec->subnet_name));
+ return;
+ }
+
+ 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));
+ return;
+ }
+ }
+ 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));
+ return;
+ }
+ }
+ else
+ {
+ DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
+ name_type));
+ return;
+ }
+
+ send_backup_list_response(subrec, work, &dgram->source_name,
+ max_number_requested, token, p->ip, p->port);
+}
+
+/*******************************************************************
+ 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;
+
+ DEBUG(1,("process_reset_browser: received diagnostic browser reset \
+request from %s IP %s state=0x%X\n",
+ 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"));
+}
+
+/*******************************************************************
+ 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;
+
+ DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
+ namestr(&dgram->source_name), inet_ntoa(p->ip),
+ 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));
+ return;
+ }
+
+ 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));
+ return;
+ }
+
+ work->needannounce = True;
+}
+
+/*******************************************************************
+ 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;
+
+ DEBUG(3,("process_lm_announce_request: Announce request from %s IP %s to %s.\n",
+ namestr(&dgram->source_name), inet_ntoa(p->ip),
+ 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));
+ return;
+ }
+
+ if(find_workgroup_on_subnet(subrec, workgroup_name) == NULL)
+ {
+ DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
+ workgroup_name));
+ return;
+ }
+
+ found_lm_clients = True;
+}
diff --git a/source/nmbd/nmbd_incomingrequests.c b/source/nmbd/nmbd_incomingrequests.c
new file mode 100644
index 00000000000..97d223b2912
--- /dev/null
+++ b/source/nmbd/nmbd_incomingrequests.c
@@ -0,0 +1,622 @@
+/*
+ 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 int DEBUGLEVEL;
+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",
+ 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",
+ 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",
+ 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",
+ 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. Error - should be sent to WINS server\n",
+ namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+
+ 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", 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",
+ 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", 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",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", 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", 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. */
+ bzero(buf,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. */
+ 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. */
+ bzero(buf,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, 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", 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",
+ 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) && (prdata != NULL))
+ 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) && (prdata != NULL))
+ 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) && (prdata != NULL))
+ free(prdata);
+}
diff --git a/source/nmbd/nmbd_lmhosts.c b/source/nmbd/nmbd_lmhosts.c
new file mode 100644
index 00000000000..158988813b7
--- /dev/null
+++ b/source/nmbd/nmbd_lmhosts.c
@@ -0,0 +1,101 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+Load a lmhosts file.
+****************************************************************************/
+void load_lmhosts_file(char *fname)
+{
+ pstring name;
+ int name_type;
+ struct in_addr ipaddr;
+ FILE *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..4486fb2840d
--- /dev/null
+++ b/source/nmbd/nmbd_logonnames.c
@@ -0,0 +1,170 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr ipzero;
+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, 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,scope);
+
+ 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..4a4e102786e
--- /dev/null
+++ b/source/nmbd/nmbd_mynames.c
@@ -0,0 +1,204 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern char **my_netbios_names;
+extern fstring global_myworkgroup;
+extern pstring scope;
+
+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",
+ namestr(nmbname), subrec->subnet_name));
+}
+
+/****************************************************************************
+ 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;
+ struct work_record *work;
+ int i;
+
+ for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ /* 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 False;
+ }
+
+ /* 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);
+ }
+
+ /* 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, scope);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type);
+
+ make_nmb_name(&nmbname, my_netbios_names[i],0x3, scope);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type);
+
+ make_nmb_name(&nmbname, my_netbios_names[i],0x0, scope);
+ 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, scope);
+ insert_permanent_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
+
+ make_nmb_name(&nmbname, global_myworkgroup, 0x1e, scope);
+ 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)
+{
+ struct subnet_record *subrec;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
+ {
+ 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;
+
+ 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 += lp_max_ttl();
+ namerec->data.refresh_time += 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..f9b2e3da9ac
--- /dev/null
+++ b/source/nmbd/nmbd_namelistdb.c
@@ -0,0 +1,637 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+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() || (*lp_wins_server()) )
+ 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 )
+ {
+ if( oldrec->data.ip )
+ free( oldrec->data.ip );
+ 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 );
+
+ if(namerec->data.ip != NULL)
+ free((char *)namerec->data.ip);
+
+ ZERO_STRUCTP(namerec);
+ free((char *)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, namestr(nmbname) ) );
+ return( NULL );
+ }
+ DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
+ subrec->subnet_name, 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, 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 );
+ }
+
+ bzero( (char *)namerec, 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);
+ free( (char *)namerec );
+ return NULL;
+ }
+
+ namerec->subnet = subrec;
+
+ make_nmb_name( &namerec->name, name, type, scope );
+ 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",
+ 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",
+ 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;
+
+ free((char *)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",
+ 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",
+ 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, 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, 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)
+ free((char *)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, FILE *fp)
+{
+ struct name_record *namerec;
+ char *src_type;
+ struct tm *tm;
+ int i;
+
+ 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 ) )
+ {
+ fprintf(fp,"\tName = %s\t", 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;
+ }
+ 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);
+ fprintf(fp, "death_time = %s\t", asctime(tm));
+ }
+ else
+ fprintf(fp, "death_time = PERMANENT\t");
+
+ if(namerec->data.refresh_time != PERMANENT_TTL)
+ {
+ tm = LocalTime(&namerec->data.refresh_time);
+ fprintf(fp, "refresh_time = %s\n", asctime(tm));
+ }
+ else
+ fprintf(fp, "refresh_time = PERMANENT\n");
+
+ fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
+ for(i = 0; i < namerec->data.num_ips; i++)
+ fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
+
+ 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)
+{
+ pstring fname;
+ FILE *fp;
+ struct subnet_record *subrec;
+
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ pstrcat(fname,"/");
+ pstrcat(fname,"namelist.debug");
+
+ fp = fopen(fname,"w");
+
+ if (!fp)
+ {
+ DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
+ fname,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 );
+ fclose( fp );
+}
diff --git a/source/nmbd/nmbd_namequery.c b/source/nmbd/nmbd_namequery.c
new file mode 100644
index 00000000000..7c2b0d4d760
--- /dev/null
+++ b/source/nmbd/nmbd_namequery.c
@@ -0,0 +1,265 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+
+/****************************************************************************
+ 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;
+
+ /* 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. */
+
+ DEBUG(5,("query_name_response: WACK from WINS server %s in querying \
+name %s on subnet %s.\n", inet_ntoa(p->ip), namestr(question_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 if(nmb->header.rcode != 0)
+ {
+ success = False;
+
+ DEBUG(5,("query_name_response: On subnet %s - negative response \
+from IP %s for name %s. Error code was %d.\n", subrec->subnet_name, inet_ntoa(p->ip),
+ namestr(question_name), nmb->header.rcode));
+ }
+ else
+ {
+ success = True;
+
+ putip((char *)&answer_ip,&nmb->answers->rdata[2]);
+ DEBUG(5,("query_name_response: On subnet %s - positive response from IP %s \
+for name %s. IP of that name is %s\n", subrec->subnet_name, inet_ntoa(p->ip),
+ namestr(question_name), 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)
+ {
+ DEBUG(0,("query_name_response: Multiple (%d) responses received for a query on \
+subnet %s for name %s. This response was from IP %s\n",
+ rrec->num_msgs, subrec->subnet_name, namestr(question_name),
+ inet_ntoa(p->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)
+ (*rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
+ else if( rrec->fail_fn)
+ (*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)
+ {
+ DEBUG(5,("query_name_timeout_response: No response to querying name %s on subnet %s.\n",
+ namestr(question_name), subrec->subnet_name));
+
+ if(rrec->fail_fn)
+ (*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, scope);
+
+ /*
+ * 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;
+
+ bzero((char *)&rrec, 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)
+ {
+ DEBUG(0,("query_name: nmbd internal error - there are %d ip addresses for name %s.\n",
+ namerec->data.num_ips, 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)
+ (*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)
+ {
+ DEBUG(0,("query_name: Failed to send packet trying to query name %s\n",
+ 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, scope);
+
+ if(queue_query_name_from_wins_server( ip_to,
+ query_name_response,
+ query_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ &nmbname) == NULL)
+ {
+ DEBUG(0,("query_name_from_wins_server: Failed to send packet trying to query name %s\n",
+ 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..05b549d30f5
--- /dev/null
+++ b/source/nmbd/nmbd_nameregister.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.
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+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(!nmb_name_equal(question_name, answer_name))
+ {
+ DEBUG(0,("register_name_response: Answer name %s differs from question \
+name %s.\n", namestr(answer_name), 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", 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",
+ 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),
+ 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), 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", 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)
+ (*rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
+ }
+ else
+ {
+ if( rrec->fail_fn)
+ (*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;
+
+ 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", 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)
+ (*rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
+ }
+ else
+ {
+ if( rrec->fail_fn)
+ (*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", namestr(nmbname), inet_ntoa(ip_list[i]) ));
+
+ free((char *)ip_list);
+ return True;
+ }
+ }
+
+ free((char *)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, scope);
+
+ /* 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",
+ 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",
+ 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..558ab6ab160
--- /dev/null
+++ b/source/nmbd/nmbd_namerelease.c
@@ -0,0 +1,238 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+
+/****************************************************************************
+ 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", namestr(answer_name), 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", 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),
+ 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), 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", namestr(answer_name), subrec->subnet_name));
+
+ if(success)
+ {
+ putip((char*)&released_ip ,&nmb->answers->rdata[2]);
+
+ if(rrec->success_fn)
+ (*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)
+ (*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", namestr(question_name), subrec->subnet_name));
+
+ if(success && rrec->success_fn)
+ {
+ if(rrec->success_fn)
+ (*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)
+ (*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",
+ 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",
+ 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..196c0f0ba72
--- /dev/null
+++ b/source/nmbd/nmbd_nodestatus.c
@@ -0,0 +1,99 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern pstring scope;
+
+/****************************************************************************
+ 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", namestr(answer_name), namestr(question_name)));
+ return;
+ }
+
+ DEBUG(5,("node_status_response: response from name %s on subnet %s.\n",
+ namestr(answer_name), subrec->subnet_name));
+
+ /* Just send the whole answer resource record for the success function
+ to parse. */
+ if(rrec->success_fn)
+ (*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",
+ 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", 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..a515ea548eb
--- /dev/null
+++ b/source/nmbd/nmbd_packets.c
@@ -0,0 +1,1959 @@
+/*
+ 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 DEBUGLEVEL;
+
+extern int num_response_packets;
+
+extern pstring scope;
+extern struct in_addr loopback_ip;
+
+static void queue_packet(struct packet_struct *packet);
+
+/*******************************************************************
+ 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 = outbuf[i+j];
+ if (x < 32 || x > 127)
+ x = '.';
+
+ if (i+j >= len)
+ break;
+ DEBUGADD( 4, ( "%c", x ) );
+ }
+
+ DEBUGADD( 4, ( " hex ") );
+
+ 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)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.
+**************************************************************************/
+
+static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname,
+ BOOL bcast,
+ 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;
+ }
+
+ bzero((char *)packet,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 = False;
+ 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;
+ }
+
+ bzero((char *)nmb->additional,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;
+
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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;
+ BOOL bcast = (subrec == unicast_subnet) ? False : True;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname, bcast,
+ 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 bcast = False;
+ 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, bcast,
+ 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)
+{
+ BOOL bcast = (subrec == unicast_subnet) ? False : True;
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname, bcast,
+ 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(bcast)
+ {
+ 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)
+{
+ BOOL bcast = (subrec == unicast_subnet) ? False : True;
+ struct packet_struct *p;
+ struct response_record *rrec;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(&namerec->name, bcast,
+ 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;
+ BOOL bcast = True;
+
+ if ((subrec == unicast_subnet) || (subrec == wins_server_subnet))
+ bcast = False;
+
+ if(assert_check_subnet(subrec))
+ return NULL;
+
+ if(( p = create_and_init_netbios_packet(nmbname, bcast,
+ subrec->bcast_ip)) == NULL)
+ return NULL;
+
+ 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;
+ BOOL bcast = False;
+
+ if(( p = create_and_init_netbios_packet(nmbname, bcast, 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;
+ BOOL bcast = False;
+
+ /* 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, bcast,
+ 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, 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, 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;
+
+ bzero((char*)&nmb->question,sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ bzero((char*)nmb->answers,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);
+
+ /* 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,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, 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), 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);
+
+ /* This is one occasion where we change a subnet that is
+ given to us. If the packet was sent to WORKGROUP<1b> instead
+ of WORKGROUP<1d> then it was unicast to us a domain master
+ browser. Change subrec to unicast.
+ */
+ if(dgram->dest_name.name_type == 0x1b)
+ subrec = unicast_subnet;
+
+ 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", 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, namestr(&dgram->source_name),
+ inet_ntoa(p->ip), 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, namestr(&dgram->source_name),
+ inet_ntoa(p->ip), 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);
+
+ /* 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,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, 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), 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, namestr(&dgram->source_name),
+ inet_ntoa(p->ip), 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))
+ {
+ DEBUG(5,("process_dgram: ignoring dgram packet sent to name %s from %s\n",
+ 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)
+ {
+ /* 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",
+ 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);
+
+ DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
+ namestr(&dgram->source_name),namestr(&dgram->dest_name),
+ inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
+
+
+ if (len <= 0)
+ return;
+
+ /* 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;
+ }
+}
+
+/****************************************************************************
+ 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(0,("find_subnet_for_nmb_packet: response record not found for response id %hu\n",
+ nmb->header.name_trn_id));
+ 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));
+
+ /* 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->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;
+ *ppset = pset;
+ *psock_array = sock_array;
+
+ return False;
+}
+
+/****************************************************************************
+ Listens for NMB or DGRAM packets, and queues them.
+***************************************************************************/
+
+BOOL listen_for_packets(BOOL run_election)
+{
+ static fd_set *listen_set = NULL;
+ static int listen_number = 0;
+ static int *sock_array = NULL;
+
+ fd_set fds;
+ int selrtn;
+ struct timeval timeout;
+#ifndef SYNC_DNS
+ int dns_fd;
+#endif
+
+ if(listen_set == NULL)
+ {
+ 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;
+ }
+ }
+
+ 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);
+#if defined(SIGUSR1)
+ BlockSignals(False, SIGUSR1);
+#endif /* SIGUSR1 */
+#if defined(SIGUSR2)
+ BlockSignals(False, SIGUSR2);
+#endif /* SIGUSR2 */
+
+ selrtn = sys_select(256,&fds,&timeout);
+
+ /* We can only take signals when we are in the select - block them again here. */
+
+ BlockSignals(True, SIGTERM);
+#if defined(SIGUSR1)
+ BlockSignals(True, SIGUSR1);
+#endif /* SIGUSR1 */
+#if defined(SIGUSR2)
+ BlockSignals(True, SIGUSR2);
+#endif /* SIGUSR2 */
+
+ if(selrtn > 0)
+ {
+ int i;
+
+#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 */
+ } /* end if selret > 0 */
+ 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];
+
+ bzero((char *)&p,sizeof(p));
+
+ if(ismyip(dest_ip))
+ loopback_this_packet = True;
+
+ generate_name_trn_id();
+
+ /* 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 = 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);
+
+ 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,
+ namestr(&dgram->source_name), inet_ntoa(src_ip)));
+ DEBUG(4,("to %s IP %s\n", 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..68a0ff40007
--- /dev/null
+++ b/source/nmbd/nmbd_processlogon.c
@@ -0,0 +1,243 @@
+/*
+ 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 int DEBUGLEVEL;
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+/****************************************************************************
+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;
+ uint16 lmnttoken;
+ uint16 lm20token;
+ uint32 domainsidsize;
+ char *getdc;
+ char *uniuser; /* Unicode user name. */
+ pstring ascuser;
+ char *unicomp; /* Unicode computer name. */
+ struct smb_passwd *smb_pass; /* To check if machine account exists */
+
+ 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 = %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),
+ dgram->dest_name.name,
+ dgram->dest_name.name_type,
+ dgram->source_name.name,
+ dgram->source_name.name_type,
+ p->ip, *iface_ip(p->ip), p->port);
+ break;
+ }
+
+ case QUERYFORPDC:
+ {
+ char *q = buf + 2;
+ char *machine = q;
+
+ getdc = skip_string(machine,1);
+ unicomp = skip_string(getdc,1);
+
+ q = align2(unicomp, buf);
+
+ q = skip_unicode_string(q, 1);
+
+ ntversion = IVAL(q, 0); q += 4;
+ lmnttoken = SVAL(q, 0); q += 2;
+ lm20token = SVAL(q, 0); q += 2;
+
+ /* 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 */
+
+ if (strcmp(mailslot, NT_LOGON_MAILSLOT)==0) {
+ q = align2(q, buf);
+
+ PutUniCode(q, my_name); /* PDC name */
+ q = skip_unicode_string(q, 1);
+ PutUniCode(q, global_myworkgroup); /* Domain name*/
+ q = skip_unicode_string(q, 1);
+
+ SIVAL(q, 0, ntversion); q += 4;
+ SSVAL(q, 0, lmnttoken); q += 2;
+ SSVAL(q, 0, lm20token); q += 2;
+ }
+
+ 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, lp_workgroup(),
+ 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),
+ dgram->dest_name.name,
+ dgram->dest_name.name_type,
+ dgram->source_name.name,
+ dgram->source_name.name_type,
+ p->ip, *iface_ip(p->ip), p->port);
+ return;
+ }
+
+ case SAMLOGON:
+ {
+ char *q = buf + 2;
+
+ unicomp = q;
+ uniuser = skip_unicode_string(unicomp,1);
+ getdc = skip_unicode_string(uniuser,1);
+ q = skip_string(getdc,1);
+ domainsidsize = IVAL(q, 0); q += 4;
+ q += domainsidsize + 3;
+ ntversion = IVAL(q, 0); q += 4;
+ lmnttoken = SVAL(q, 0); q += 2;
+ lm20token = SVAL(q, 0); q += 2;
+
+ DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
+
+ /*
+ * If MACHINE$ is in our password database then respond, else ignore.
+ * Let's ignore the SID.
+ */
+
+ pstrcpy(ascuser, unistr(uniuser));
+ DEBUG(3,("process_logon_packet: SAMLOGON user %s\n", ascuser));
+
+ fstrcpy(reply_name,"\\\\"); /* Here it wants \\LOGONSERVER. */
+ fstrcpy(reply_name+2,my_name);
+
+ smb_pass = getsmbpwnam(ascuser);
+
+ if(!smb_pass )
+ {
+ DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, not in password file\n",
+ unistr(unicomp),inet_ntoa(p->ip), ascuser));
+ return;
+ }
+ else if(smb_pass->acct_ctrl & ACB_DISABLED)
+ {
+ DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, accound disabled.\n",
+ unistr(unicomp),inet_ntoa(p->ip), ascuser));
+ return;
+ }
+ else
+ {
+ DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
+ unistr(unicomp),inet_ntoa(p->ip), ascuser, reply_name, global_myworkgroup,
+ SAMLOGON_R ,lmnttoken));
+ }
+
+ /* Construct reply. */
+
+ q = outbuf;
+ SSVAL(q, 0, SAMLOGON_R); q += 2;
+
+ PutUniCode(q, reply_name); q = skip_unicode_string(q, 1);
+ unistrcpy(q, uniuser); q = skip_unicode_string(q, 1); /* User name (workstation trust account) */
+ PutUniCode(q, lp_workgroup()); q = skip_unicode_string(q, 1); /* Domain name. */
+
+ SIVAL(q, 0, ntversion); q += 4;
+ SSVAL(q, 0, lmnttoken); q += 2;
+ SSVAL(q, 0, lm20token); q += 2;
+
+ dump_data(4, outbuf, PTR_DIFF(q, outbuf));
+
+ send_mailslot(True, getdc,
+ outbuf,PTR_DIFF(q,outbuf),
+ dgram->dest_name.name,
+ dgram->dest_name.name_type,
+ dgram->source_name.name,
+ dgram->source_name.name_type,
+ p->ip, *iface_ip(p->ip), p->port);
+ 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..3edca699812
--- /dev/null
+++ b/source/nmbd/nmbd_responserecordsdb.c
@@ -0,0 +1,267 @@
+/*
+ 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;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+
+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);
+ free((char *)rrec->userdata);
+ }
+ }
+
+ /* Ensure we can delete. */
+ rrec->packet->locked = False;
+ free_packet(rrec->packet);
+
+ ZERO_STRUCTP(rrec);
+ free((char *)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;
+ }
+
+ bzero((char *)rrec, 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);
+ 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);
+ 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 */
+
+ /* 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..38c8deafe72
--- /dev/null
+++ b/source/nmbd/nmbd_sendannounce.c
@@ -0,0 +1,610 @@
+/*
+ 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 int DEBUGLEVEL;
+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) ));
+
+ bzero(outbuf,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));
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = ANN_AnnouncementRequest;
+ p++;
+
+ CVAL(p,0) = work->token; /* (local) Unique workgroup token id. */
+ p++;
+ StrnCpy(p,global_myname,15);
+ strupper(p);
+ p = skip_string(p,1);
+
+ 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;
+
+ bzero(outbuf,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. */
+
+ StrnCpy(p+5,server_name,15);
+ strupper(p+5);
+
+ 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. */
+
+ pstrcpy(p+31,server_comment);
+ p += 31;
+ p = skip_string(p,1);
+
+ 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;
+
+ bzero(outbuf,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);
+
+ 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 = lp_serverstring();
+
+ 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(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;
+ }
+
+ bzero(outbuf,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..cf7295ee11d
--- /dev/null
+++ b/source/nmbd/nmbd_serverlistdb.c
@@ -0,0 +1,458 @@
+/*
+ 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 int DEBUGLEVEL;
+
+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);
+ free((char *)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);
+ free((char *)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;
+ }
+
+ bzero((char *)servrec,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;
+ FILE *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 = fopen(fnamenew,"w");
+
+ 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));
+ fclose(fp);
+ return;
+ }
+
+ slprintf(tmp,sizeof(tmp)-1, "\"%s\"", work->work_group);
+ fprintf(fp, "%-25s ", tmp);
+ 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);
+ fprintf(fp, "%-30s", tmp);
+ 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]);
+ fprintf(fp, "%-25s ", tmp);
+ fprintf(fp, "%08x ", stype);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", lp_serverstring());
+ fprintf(fp, "%-30s", tmp);
+ 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);
+ fprintf(fp, "%-25s ", tmp);
+
+ fprintf(fp, "%08x ", wg_type);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", work->local_master_browser_name);
+ fprintf(fp, "%-30s", tmp);
+ 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);
+ fprintf(fp, "%-25s ", tmp);
+ fprintf(fp, "%08x ", serv_type);
+ slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", servrec->serv.comment);
+ fprintf(fp, "%-30s", tmp);
+ fprintf(fp, "\"%s\"\n", work->work_group);
+ }
+ }
+ }
+ }
+
+ 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..edc930c2054
--- /dev/null
+++ b/source/nmbd/nmbd_subnetdb.c
@@ -0,0 +1,359 @@
+/*
+ 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 int DEBUGLEVEL;
+
+extern fstring myworkgroup;
+extern char **my_netbios_names;
+extern struct in_addr ipzero;
+
+/* 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)
+{
+ struct subnet_record *subrec2;
+
+ if (!subnetlist)
+ {
+ subnetlist = subrec;
+ subrec->prev = NULL;
+ subrec->next = NULL;
+ return;
+ }
+
+ for (subrec2 = subnetlist; subrec2->next; subrec2 = subrec2->next)
+ ;
+
+ subrec2->next = subrec;
+ subrec->next = NULL;
+ subrec->prev = subrec2;
+}
+
+/* ************************************************************************** **
+ * 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) ),
+ namestr(Iname), namestr(&NR->name), sizeof(struct nmb_name) );
+ }
+
+ return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
+ } /* namelist_entry_compare */
+
+/****************************************************************************
+ 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)) == -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)) == -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);
+ }
+
+ bzero( (char *)subrec, 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);
+ free((char *)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 subnet entries.
+**************************************************************************/
+
+BOOL create_subnets(void)
+{
+ int num_interfaces = iface_count();
+ int i;
+ struct in_addr unicast_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 subnet_record *subrec;
+ struct interface *iface = get_interface(i);
+
+ if((subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
+ iface->ip, iface->bcast,iface->nmask)) == NULL)
+ return False;
+ add_subnet(subrec);
+ }
+
+ /*
+ * 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.
+ */
+
+ if(*lp_wins_server())
+ {
+ struct in_addr real_wins_ip;
+ real_wins_ip = *interpret_addr2(lp_wins_server());
+
+ if (!zero_ip(real_wins_ip))
+ {
+ unicast_ip = real_wins_ip;
+ }
+ else
+ {
+ /* The smb.conf's wins server parameter MUST be a host_name
+ or an ip_address. */
+ DEBUG(0,("invalid smb.conf parameter 'wins server'\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. */
+ unicast_ip = ipzero;
+ }
+
+ /*
+ * 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);
+
+ 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 = (ip_equal(ipzero, 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..b6f54dccec0
--- /dev/null
+++ b/source/nmbd/nmbd_synclists.c
@@ -0,0 +1,290 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+
+struct sync_record {
+ struct sync_record *next, *prev;
+ fstring workgroup;
+ fstring server;
+ pstring fname;
+ struct in_addr ip;
+ int pid;
+};
+
+/* a linked list of current sync connections */
+static struct sync_record *syncs;
+
+static FILE *fp;
+
+/*******************************************************************
+ This is the NetServerEnum callback.
+ ******************************************************************/
+static void callback(char *sname, uint32 stype, char *comment)
+{
+ 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;
+ 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)) {
+ fclose(fp);
+ return;
+ }
+
+ make_nmb_name(&calling, local_machine, 0x0 , scope);
+ make_nmb_name(&called , name , nm_type, scope);
+
+ if (!cli_session_request(&cli, &calling, &called))
+ {
+ cli_shutdown(&cli);
+ fclose(fp);
+ 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;
+ }
+
+ /* Fetch a workgroup list. */
+ cli_NetServerEnum(&cli, workgroup,
+ local_type|SV_TYPE_DOMAIN_ENUM,
+ callback);
+
+ /* Now fetch a server list. */
+ if (servers) {
+ cli_NetServerEnum(&cli, workgroup,
+ local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
+ callback);
+ }
+
+ 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;
+
+ /* 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)) {
+ return;
+ }
+
+ s = (struct sync_record *)malloc(sizeof(*s));
+ if (!s) return;
+
+ 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++);
+ string_sub(s->fname,"//", "/");
+
+ DLIST_ADD(syncs, s);
+
+ /* the parent forks and returns, leaving the child to do the
+ actual sync */
+ CatchChild();
+ if ((s->pid = fork())) return;
+
+ BlockSignals( False, SIGTERM );
+
+ DEBUG(2,("Initiating browse sync for %s to %s(%s)\n",
+ work->work_group, name, inet_ntoa(ip)));
+
+ fp = fopen(s->fname,"w");
+ if (!fp) _exit(1);
+
+ sync_child(name, nm_type, work->work_group, ip, local, servers,
+ s->fname);
+
+ fclose(fp);
+ _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)
+{
+ FILE *f;
+ fstring server, type_str;
+ unsigned type;
+ pstring comment;
+ pstring line;
+ char *ptr;
+ int count=0;
+
+ f = fopen(s->fname,"r");
+
+ if (!f) return;
+
+ while (!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++;
+ }
+
+ 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);
+ free(s);
+ }
+ }
+}
diff --git a/source/nmbd/nmbd_winsproxy.c b/source/nmbd/nmbd_winsproxy.c
new file mode 100644
index 00000000000..2084d3915ab
--- /dev/null
+++ b/source/nmbd/nmbd_winsproxy.c
@@ -0,0 +1,224 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+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", 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)
+ free((char *)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",
+ 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, 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)
+ {
+ free((char *)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);
+ free((char *)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)
+{
+ char ud[sizeof(struct userdata_struct) + sizeof(struct subrec *) +
+ sizeof(struct packet_struct *)];
+ struct userdata_struct *userdata = (struct userdata_struct *)ud;
+
+ bzero(ud, 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..80825579c42
--- /dev/null
+++ b/source/nmbd/nmbd_winsserver.c
@@ -0,0 +1,1612 @@
+/*
+ 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
+
+extern int DEBUGLEVEL;
+extern struct in_addr ipzero;
+
+
+
+/****************************************************************************
+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)
+{
+ pstring fname;
+ time_t time_now = time(NULL);
+ FILE *fp;
+ pstring line;
+
+ if(!lp_we_are_a_wins_server())
+ return True;
+
+ add_samba_names_to_subnet(wins_server_subnet);
+
+#ifndef SYNC_DNS
+ /* Setup the async dns. */
+ start_async_dns();
+#endif
+
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ pstrcat(fname,"/");
+ pstrcat(fname,WINS_LIST);
+
+ if((fp = fopen(fname,"r")) == NULL)
+ {
+ DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
+ fname, strerror(errno) ));
+ return True;
+ }
+
+ while (!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));
+ 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(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));
+ free((char *)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(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));
+ }
+
+ free((char *)ip_list);
+ }
+
+ 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",
+ 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", 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", 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", 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);
+ 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", 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), 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", 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",
+ 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", 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", 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",
+ 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.", 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), 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", 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", 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);
+ 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 );
+ 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 )
+ {
+ char ud[sizeof(struct userdata_struct) + sizeof(struct packet_struct *)];
+ 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 );
+
+ 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", 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);
+
+ 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), 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",
+ 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",
+ 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", 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.", 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", 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",
+ 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", 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", 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);
+ 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);
+ return;
+ }
+
+ /*
+ * If the name exists do a query to the owner
+ * to see if they still want the name.
+ */
+
+ if(namerec != NULL)
+ {
+ char ud[sizeof(struct userdata_struct) + sizeof(struct packet_struct *)];
+ 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( p->ip,
+ 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 );
+
+ 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. */
+
+ 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;
+
+ bzero(rdata,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) && (prdata != NULL))
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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", 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.", 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",
+ 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);
+
+ /*
+ * 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;
+
+ FILE *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 (fork()) {
+ return;
+ }
+ }
+
+ slprintf(fname,sizeof(fname),"%s/%s", lp_lockdir(), WINS_LIST);
+ string_sub(fname,"//", "/");
+ slprintf(fnamenew,sizeof(fnamenew),"%s.%u", fname, (unsigned int)getpid());
+
+ if((fp = fopen(fnamenew,"w")) == 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"));
+
+ 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 ", namestr(&namerec->name) ));
+
+ if( namerec->data.death_time != PERMANENT_TTL )
+ {
+ tm = LocalTime(&namerec->data.death_time);
+ DEBUGADD(4,("TTL = %s", asctime(tm) ));
+ }
+ else
+ DEBUGADD(4,("TTL = PERMANENT\t"));
+
+ 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 )
+ {
+ 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++)
+ fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
+ fprintf( fp, "%2xR\n", namerec->data.nb_flags );
+ }
+ }
+
+ 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..ac25127e82c
--- /dev/null
+++ b/source/nmbd/nmbd_workgroupdb.c
@@ -0,0 +1,366 @@
+/*
+ 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 int DEBUGLEVEL;
+
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+extern uint16 samba_nb_type;
+extern struct in_addr ipzero;
+
+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)
+{
+ struct work_record *w2;
+
+ work->subnet = subrec;
+
+ if (!subrec->workgrouplist)
+ {
+ subrec->workgrouplist = work;
+ work->prev = NULL;
+ work->next = NULL;
+ return;
+ }
+
+ for (w2 = subrec->workgrouplist; w2->next; w2 = w2->next)
+ ;
+
+ w2->next = work;
+ work->next = NULL;
+ work->prev = w2;
+
+ subrec->work_changed = True;
+}
+
+/****************************************************************************
+ Create an empty workgroup.
+ **************************************************************************/
+
+static struct work_record *create_workgroup(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;
+ }
+ bzero((char *)work, 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';
+ putip((char *)&work->dmb_addr, &ipzero);
+
+ /* 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);
+ free((char *)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,
+ fstring 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,
+ fstring 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",
+ 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, lp_serverstring());
+ 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/param/.cvsignore b/source/param/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/param/.cvsignore
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index c61ab26781f..05ed6484ac5 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -2,7 +2,7 @@
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
@@ -49,29 +49,33 @@
#include "includes.h"
-#include "params.h"
-#include "loadparm.h"
-#include "pcap.h"
+/* Set default coding system for KANJI if none specified in Makefile. */
+/*
+ * We treat KANJI specially due to historical precedent (it was the
+ * first non-english codepage added to Samba). With the new dynamic
+ * codepage support this is not needed anymore.
+ *
+ * The define 'KANJI' is being overloaded to mean 'use kanji codepage
+ * by default' and also 'this is the filename-to-disk conversion
+ * method to use'. This really should be removed and all control
+ * over this left in the smb.conf parameters 'client codepage'
+ * and 'coding system'.
+ */
+#ifndef KANJI
+#define KANJI "sbcs"
+#endif /* KANJI */
+BOOL in_client = False; /* Not in the client by default */
BOOL bLoaded = False;
extern int DEBUGLEVEL;
-extern int ReadSize;
extern pstring user_socket_options;
-extern pstring smbrun_path;
+extern pstring global_myname;
#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
@@ -86,81 +90,149 @@ extern pstring smbrun_path;
#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;
-
-typedef enum
-{
- P_LOCAL,P_GLOBAL,P_NONE
-} parm_class;
-
-int keepalive=0;
+int keepalive=DEFAULT_KEEPALIVE;
extern BOOL use_getwd_cache;
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;
+ 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 *szDomainAdminGroup;
+ char *szDomainGuestGroup;
+ char *szDomainAdminUsers;
+ char *szDomainGuestUsers;
+ char *szDomainHostsallow;
+ char *szDomainHostsdeny;
+ char *szUsernameMap;
+#ifdef USING_GROUPNAME_MAP
+ char *szGroupnameMap;
+#endif /* USING_GROUPNAME_MAP */
+ char *szCharacterSet;
+ char *szLogonScript;
+ char *szLogonPath;
+ char *szLogonDrive;
+ char *szLogonHome;
+ char *szSmbrun;
+ char *szWINSserver;
+ char *szCodingSystem;
+ char *szInterfaces;
+ char *szRemoteAnnounce;
+ char *szRemoteBrowseSync;
+ char *szSocketAddress;
+ char *szNISHomeMapName;
+ char *szAnnounceVersion; /* This is initialised in init_globals */
+ char *szNetbiosAliases;
+ char *szDomainSID;
+ char *szDomainOtherSIDs;
+ char *szDomainGroups;
+ char *szDriverFile;
+ char *szNameResolveOrder;
+ char *szLdapServer;
+ char *szLdapSuffix;
+ char *szLdapFilter;
+ char *szLdapRoot;
+ char *szLdapRootPassword;
+ char *szPanicAction;
+ int max_log_size;
+ int mangled_stack;
+ int max_xmit;
+ int max_mux;
+ int max_packet;
+ int pwordlevel;
+ int unamelevel;
+ int deadtime;
+ int maxprotocol;
+ int security;
+ int maxdisksize;
+ int lpqcachetime;
+ int syslog;
+ int os_level;
+ int max_ttl;
+ int max_wins_ttl;
+ int min_wins_ttl;
+ int ReadSize;
+ int lm_announce;
+ int lm_interval;
+ int shmem_size;
+ int client_code_page;
+ int announce_as; /* This is initialised in init_globals */
+ int machine_password_timeout;
+ int change_notify_timeout;
+ int stat_cache_size;
+#ifdef WITH_LDAP
+ int ldap_port;
+#endif /* WITH_LDAP */
+#ifdef WITH_SSL
+ int sslVersion;
+ char *sslHostsRequire;
+ char *sslHostsResign;
+ char *sslCaCertDir;
+ char *sslCaCertFile;
+ char *sslCert;
+ char *sslPrivKey;
+ char *sslClientCert;
+ char *sslClientPrivKey;
+ char *sslCiphers;
+ BOOL sslEnabled;
+ BOOL sslReqClientCert;
+ BOOL sslReqServerCert;
+ BOOL sslCompatibility;
+#endif /* WITH_SSL */
+ BOOL bDNSproxy;
+ BOOL bWINSsupport;
+ BOOL bWINSproxy;
+ BOOL bLocalMaster;
+ BOOL bPreferredMaster;
+ BOOL bDomainController;
+ BOOL bDomainMaster;
+ BOOL bDomainLogons;
+ BOOL bEncryptPasswords;
+ BOOL bUpdateEncrypt;
+ BOOL bStripDot;
+ BOOL bNullPasswords;
+ BOOL bLoadPrinters;
+ BOOL bUseRhosts;
+ BOOL bReadRaw;
+ BOOL bWriteRaw;
+ BOOL bReadPrediction;
+ BOOL bReadbmpx;
+ BOOL bSyslogOnly;
+ BOOL bBrowseList;
+ BOOL bUnixRealname;
+ BOOL bNISHomeMap;
+ BOOL bTimeServer;
+ BOOL bBindInterfacesOnly;
+ BOOL bNetWkstaUserLogon;
+ BOOL bUnixPasswdSync;
+ BOOL bPasswdChatDebug;
+ BOOL bOleLockingCompat;
+ BOOL bTimestampLogs;
+ BOOL bNTSmbSupport;
+ BOOL bStatCache;
+ BOOL bKernelOplocks;
} global;
static global Globals;
@@ -191,23 +263,35 @@ typedef struct
char *szLprmcommand;
char *szLppausecommand;
char *szLpresumecommand;
+ char *szQueuepausecommand;
+ char *szQueueresumecommand;
char *szPrintername;
+ char *szPrinterDriver;
+ char *szPrinterDriverLocation;
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 *volume;
+ char *fstype;
int iMinPrintSpace;
- int iCreate_mode;
+ int iCreate_mask;
+ int iCreate_force_mode;
+ int iDir_mask;
+ int iDir_force_mode;
int iMaxConnections;
int iDefaultCase;
+ int iPrinting;
BOOL bAlternatePerm;
BOOL bRevalidate;
BOOL bCaseSensitive;
@@ -230,12 +314,22 @@ typedef struct
BOOL bLocking;
BOOL bStrictLocking;
BOOL bShareModes;
+ BOOL bOpLocks;
BOOL bOnlyUser;
BOOL bMangledNames;
BOOL bWidelinks;
+ BOOL bSymlinks;
BOOL bSyncAlways;
+ BOOL bStrictSync;
char magic_char;
BOOL *copymap;
+ BOOL bDeleteReadonly;
+ BOOL bFakeOplocks;
+ BOOL bDeleteVetoFiles;
+ BOOL bDosFiletimes;
+ BOOL bDosFiletimeResolution;
+ BOOL bFakeDirCreateTimes;
+ BOOL bBlockingLocks;
char dummy[3]; /* for alignment */
} service;
@@ -247,7 +341,7 @@ static service sDefault =
NULL, /* szService */
NULL, /* szPath */
NULL, /* szUsername */
- NULL, /* szGuestAccount */
+ NULL, /* szGuestAccount - this is set in init_globals() */
NULL, /* szInvalidUsers */
NULL, /* szValidUsers */
NULL, /* szAdminUsers */
@@ -262,28 +356,40 @@ static service sDefault =
NULL, /* szLprmcommand */
NULL, /* szLppausecommand */
NULL, /* szLpresumecommand */
+ NULL, /* szQueuepausecommand */
+ NULL, /* szQueueresumecommand */
NULL, /* szPrintername */
+ NULL, /* szPrinterDriver - this is set in init_globals() */
+ NULL, /* szPrinterDriverLocation */
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, /* volume */
+ NULL, /* fstype */
0, /* iMinPrintSpace */
- 0755, /* iCreate_mode */
+ 0744, /* iCreate_mask */
+ 0000, /* iCreate_force_mode */
+ 0755, /* iDir_mask */
+ 0000, /* iDir_force_mode */
0, /* iMaxConnections */
CASE_LOWER, /* iDefaultCase */
+ DEFAULT_PRINTING, /* iPrinting */
False, /* bAlternatePerm */
False, /* revalidate */
False, /* case sensitive */
- False, /* case preserve */
- False, /* short case preserve */
+ True, /* case preserve */
+ True, /* short case preserve */
False, /* case mangle */
True, /* status */
True, /* bHideDotFiles */
@@ -301,12 +407,22 @@ static service sDefault =
True, /* bLocking */
False, /* bStrictLocking */
True, /* bShareModes */
+ True, /* bOpLocks */
False, /* bOnlyUser */
True, /* bMangledNames */
True, /* bWidelinks */
+ True, /* bSymlinks */
False, /* bSyncAlways */
+ False, /* bStrictSync */
'~', /* magic char */
NULL, /* copymap */
+ False, /* bDeleteReadonly */
+ False, /* bFakeOplocks */
+ False, /* bDeleteVetoFiles */
+ False, /* bDosFiletimes */
+ False, /* bDosFiletimeResolution */
+ False, /* bFakeDirCreateTimes */
+ True, /* bBlockingLocks */
"" /* dummy */
};
@@ -318,7 +434,7 @@ static int iNumServices = 0;
static int iServiceIndex = 0;
static BOOL bInGlobalSection = True;
static BOOL bGlobalOnly = False;
-
+static int default_server_announce;
#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
@@ -326,175 +442,321 @@ static BOOL bGlobalOnly = False;
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 */
+static BOOL handle_character_set(char *pszParmValue,char **ptr);
+static BOOL handle_coding_system(char *pszParmValue,char **ptr);
-struct parm_struct
-{
- char *label;
- parm_type type;
- parm_class class;
- void *ptr;
- BOOL (*special)();
-} parm_table[] =
+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"},
+ {-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"},
+ {-1, NULL}};
+
+static struct enum_list enum_announce_as[] = {{ANNOUNCE_AS_NT, "NT"}, {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_lm_announce[] = {{0, "False"}, {1, "True"}, {2, "Auto"}, {-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
+
+/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
+static struct parm_struct 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}
+ {"Base Options", P_SEP, P_SEPARATOR},
+ {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL, FLAG_BASIC|FLAG_PRINT},
+ {"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_BASIC|FLAG_PRINT},
+ {"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, 0},
+ {"workgroup", P_USTRING, P_GLOBAL, &Globals.szWorkGroup, NULL, NULL, FLAG_BASIC},
+ {"netbios name", P_UGSTRING,P_GLOBAL, global_myname, NULL, NULL, FLAG_BASIC},
+ {"netbios aliases", P_STRING, P_GLOBAL, &Globals.szNetbiosAliases, NULL, NULL, 0},
+ {"server string", P_STRING, P_GLOBAL, &Globals.szServerString, NULL, NULL, FLAG_BASIC},
+ {"interfaces", P_STRING, 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},
+ {"encrypt passwords",P_BOOL, P_GLOBAL, &Globals.bEncryptPasswords, NULL, NULL, FLAG_BASIC},
+ {"update encrypted", P_BOOL, P_GLOBAL, &Globals.bUpdateEncrypt, NULL, NULL, FLAG_BASIC},
+ {"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL, NULL, 0},
+ {"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, 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},
+ {"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, 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},
+ {"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},
+ {"alternate permissions",P_BOOL,P_LOCAL, &sDefault.bAlternatePerm, NULL, NULL, FLAG_GLOBAL|FLAG_DEPRECATED},
+ {"revalidate", P_BOOL, P_LOCAL, &sDefault.bRevalidate, NULL, NULL, FLAG_GLOBAL},
+ {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_GLOBAL},
+ {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, 0},
+ {"users", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, 0},
+ {"guest account", P_STRING, P_LOCAL, &sDefault.szGuestaccount, NULL, NULL, FLAG_BASIC|FLAG_PRINT|FLAG_GLOBAL},
+ {"invalid users", P_STRING, P_LOCAL, &sDefault.szInvalidUsers, NULL, NULL, FLAG_GLOBAL},
+ {"valid users", P_STRING, P_LOCAL, &sDefault.szValidUsers, NULL, NULL, FLAG_GLOBAL},
+ {"admin users", P_STRING, P_LOCAL, &sDefault.szAdminUsers, NULL, NULL, FLAG_GLOBAL},
+ {"read list", P_STRING, P_LOCAL, &sDefault.readlist, NULL, NULL, FLAG_GLOBAL},
+ {"write list", P_STRING, P_LOCAL, &sDefault.writelist, NULL, NULL, FLAG_GLOBAL},
+ {"force user", P_STRING, P_LOCAL, &sDefault.force_user, NULL, NULL, 0},
+ {"force group", P_STRING, P_LOCAL, &sDefault.force_group, NULL, NULL, 0},
+ {"group", P_STRING, P_LOCAL, &sDefault.force_group, NULL, NULL, 0},
+ {"read only", P_BOOL, P_LOCAL, &sDefault.bRead_only, NULL, NULL, FLAG_BASIC},
+ {"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},
+ {"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},
+ {"directory mask", P_OCTAL, P_LOCAL, &sDefault.iDir_mask, NULL, NULL, FLAG_GLOBAL},
+ {"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},
+ {"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, 0},
+ {"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_PRINT},
+ {"public", P_BOOL, P_LOCAL, &sDefault.bGuest_ok, NULL, NULL, 0},
+ {"only user", P_BOOL, P_LOCAL, &sDefault.bOnlyUser, NULL, NULL, 0},
+ {"hosts allow", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL, NULL, FLAG_GLOBAL|FLAG_BASIC|FLAG_PRINT},
+ {"allow hosts", P_STRING, P_LOCAL, &sDefault.szHostsallow, NULL, NULL, 0},
+ {"hosts deny", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL|FLAG_BASIC|FLAG_PRINT},
+ {"deny hosts", P_STRING, 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_STRING, P_GLOBAL, &Globals.sslHostsRequire, NULL, NULL, 0 },
+ {"ssl hosts resign", P_STRING, 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.sslCert, NULL, NULL, 0 },
+ {"ssl server key", P_STRING, P_GLOBAL, &Globals.sslPrivKey, 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 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, NULL, NULL, FLAG_BASIC},
+ {"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, 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},
+ {"status", P_BOOL, P_LOCAL, &sDefault.status, NULL, NULL, FLAG_GLOBAL},
+
+ {"Protocol Options", P_SEP, P_SEPARATOR},
+ {"protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, 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},
+ {"networkstation user login", P_BOOL,P_GLOBAL, &Globals.bNetWkstaUserLogon,NULL, NULL, 0},
+ {"nt smb support", P_BOOL, P_GLOBAL, &Globals.bNTSmbSupport, 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},
+
+ {"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 connections", P_INTEGER, P_LOCAL, &sDefault.iMaxConnections, NULL, NULL, 0},
+ {"max disk size", P_INTEGER, P_GLOBAL, &Globals.maxdisksize, NULL, NULL, 0},
+ {"min print space", P_INTEGER, P_LOCAL, &sDefault.iMinPrintSpace, NULL, NULL, 0},
+ {"read prediction", P_BOOL, P_GLOBAL, &Globals.bReadPrediction, NULL, NULL, 0},
+ {"read size", P_INTEGER, P_GLOBAL, &Globals.ReadSize, NULL, NULL, 0},
+ {"shared mem size", P_INTEGER, P_GLOBAL, &Globals.shmem_size, 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 sync", P_BOOL, P_LOCAL, &sDefault.bStrictSync, NULL, NULL, 0},
+ {"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL, NULL, 0},
+
+ {"Printing Options", P_SEP, P_SEPARATOR},
+ {"load printers", P_BOOL, P_GLOBAL, &Globals.bLoadPrinters, NULL, NULL, 0},
+ {"printcap name", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL, 0},
+ {"printcap", P_STRING, P_GLOBAL, &Globals.szPrintcapname, NULL, NULL, 0},
+ {"printer driver file", P_STRING, P_GLOBAL, &Globals.szDriverFile, NULL, NULL, 0},
+ {"print ok", P_BOOL, P_LOCAL, &sDefault.bPrint_ok, NULL, NULL, 0},
+ {"printable", 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},
+ {"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_GLOBAL},
+ {"lpresume command", P_STRING, P_LOCAL, &sDefault.szLpresumecommand,NULL, NULL, FLAG_GLOBAL},
+ {"queuepause command", P_STRING, P_LOCAL, &sDefault.szQueuepausecommand, NULL, NULL, FLAG_GLOBAL},
+ {"queueresume command", P_STRING, P_LOCAL, &sDefault.szQueueresumecommand, NULL, NULL, FLAG_GLOBAL},
+
+ {"printer name", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, FLAG_PRINT},
+ {"printer", P_STRING, P_LOCAL, &sDefault.szPrintername, NULL, NULL, 0},
+ {"printer driver", P_STRING, P_LOCAL, &sDefault.szPrinterDriver, NULL, NULL, 0},
+ {"printer driver location", P_STRING, P_LOCAL, &sDefault.szPrinterDriverLocation, NULL, NULL, FLAG_GLOBAL},
+
+
+ {"Filename Handling", P_SEP, P_SEPARATOR},
+ {"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL, NULL, 0},
+ {"character set", P_STRING, P_GLOBAL, &Globals.szCharacterSet, handle_character_set, NULL, 0},
+ {"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL, NULL, 0},
+ {"coding system", P_STRING, P_GLOBAL, &Globals.szCodingSystem, handle_coding_system, NULL, 0},
+ {"client code page", P_INTEGER, P_GLOBAL, &Globals.client_code_page, NULL, NULL, 0},
+ {"default case", P_ENUM, P_LOCAL, &sDefault.iDefaultCase, NULL, enum_case, 0},
+ {"case sensitive", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, FLAG_GLOBAL},
+ {"casesignames", P_BOOL, P_LOCAL, &sDefault.bCaseSensitive, NULL, NULL, 0},
+ {"preserve case", P_BOOL, P_LOCAL, &sDefault.bCasePreserve, NULL, NULL, FLAG_GLOBAL},
+ {"short preserve case",P_BOOL, P_LOCAL, &sDefault.bShortCasePreserve,NULL, NULL, FLAG_GLOBAL},
+ {"mangle case", P_BOOL, P_LOCAL, &sDefault.bCaseMangle, NULL, NULL, FLAG_GLOBAL},
+ {"mangling char", P_CHAR, P_LOCAL, &sDefault.magic_char, NULL, NULL, FLAG_GLOBAL},
+ {"hide dot files", P_BOOL, P_LOCAL, &sDefault.bHideDotFiles, NULL, NULL, FLAG_GLOBAL},
+ {"delete veto files",P_BOOL, P_LOCAL, &sDefault.bDeleteVetoFiles, NULL, NULL, FLAG_GLOBAL},
+ {"veto files", P_STRING, P_LOCAL, &sDefault.szVetoFiles, NULL, NULL, FLAG_GLOBAL},
+ {"hide files", P_STRING, P_LOCAL, &sDefault.szHideFiles, NULL, NULL, FLAG_GLOBAL},
+ {"veto oplock files",P_STRING, P_LOCAL, &sDefault.szVetoOplockFiles,NULL, NULL, FLAG_GLOBAL},
+ {"map system", P_BOOL, P_LOCAL, &sDefault.bMap_system, NULL, NULL, FLAG_GLOBAL},
+ {"map hidden", P_BOOL, P_LOCAL, &sDefault.bMap_hidden, NULL, NULL, FLAG_GLOBAL},
+ {"map archive", P_BOOL, P_LOCAL, &sDefault.bMap_archive, NULL, NULL, FLAG_GLOBAL},
+ {"mangled names", P_BOOL, P_LOCAL, &sDefault.bMangledNames, NULL, NULL, FLAG_GLOBAL},
+ {"mangled map", P_STRING, P_LOCAL, &sDefault.szMangledMap, NULL, NULL, FLAG_GLOBAL},
+ {"stat cache", P_BOOL, P_GLOBAL, &Globals.bStatCache, NULL, NULL, 0},
+
+ {"Domain Options", P_SEP, P_SEPARATOR},
+ {"domain sid", P_USTRING, P_GLOBAL, &Globals.szDomainSID, NULL, NULL, 0},
+ {"domain groups", P_STRING, P_GLOBAL, &Globals.szDomainGroups, NULL, NULL, 0},
+ {"domain controller",P_BOOL , P_GLOBAL, &Globals.bDomainController,NULL, NULL, 0},
+ {"domain admin group",P_STRING, P_GLOBAL, &Globals.szDomainAdminGroup, NULL, NULL, 0},
+ {"domain guest group",P_STRING, P_GLOBAL, &Globals.szDomainGuestGroup, NULL, NULL, 0},
+ {"domain admin users",P_STRING, P_GLOBAL, &Globals.szDomainAdminUsers, NULL, NULL, 0},
+ {"domain guest users",P_STRING, P_GLOBAL, &Globals.szDomainGuestUsers, NULL, NULL, 0},
+#ifdef USING_GROUPNAME_MAP
+ {"groupname map", P_STRING, P_GLOBAL, &Globals.szGroupnameMap, NULL, NULL, 0},
+#endif /* USING_GROUPNAME_MAP */
+ {"machine password timeout", P_INTEGER, P_GLOBAL, &Globals.machine_password_timeout, NULL, NULL, 0},
+
+ {"Logon Options", P_SEP, P_SEPARATOR},
+ {"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_lm_announce, 0},
+ {"lm interval", P_INTEGER, P_GLOBAL, &Globals.lm_interval, NULL, NULL, 0},
+ {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL, NULL, FLAG_BASIC},
+ {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL, NULL, 0},
+ {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL, NULL, FLAG_BASIC},
+ {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL, NULL, FLAG_BASIC},
+ {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL, NULL, 0},
+ {"browseable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, 0},
+ {"browsable", P_BOOL, P_LOCAL, &sDefault.bBrowseable, NULL, NULL, 0},
+
+ {"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, NULL, NULL, FLAG_BASIC},
+ {"wins support", P_BOOL, P_GLOBAL, &Globals.bWINSsupport, NULL, NULL, FLAG_BASIC},
+
+ {"Locking Options", P_SEP, P_SEPARATOR},
+ {"blocking locks", P_BOOL, P_LOCAL, &sDefault.bBlockingLocks, NULL, NULL, 0},
+ {"fake oplocks", P_BOOL, P_LOCAL, &sDefault.bFakeOplocks, NULL, NULL, 0},
+ {"kernel oplocks", P_BOOL, P_GLOBAL, &Globals.bKernelOplocks, NULL, NULL, FLAG_GLOBAL},
+ {"locking", P_BOOL, P_LOCAL, &sDefault.bLocking, NULL, NULL, FLAG_GLOBAL},
+ {"ole locking compatibility", P_BOOL, P_GLOBAL, &Globals.bOleLockingCompat, NULL, NULL, FLAG_GLOBAL},
+ {"oplocks", P_BOOL, P_LOCAL, &sDefault.bOpLocks, NULL, NULL, FLAG_GLOBAL},
+ {"strict locking", P_BOOL, P_LOCAL, &sDefault.bStrictLocking, NULL, NULL, FLAG_GLOBAL},
+ {"share modes", P_BOOL, P_LOCAL, &sDefault.bShareModes, NULL, NULL, FLAG_GLOBAL},
+
+#ifdef WITH_LDAP
+ {"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 root", P_STRING, P_GLOBAL, &Globals.szLdapRoot, NULL, NULL, 0},
+ {"ldap root passwd", P_STRING, P_GLOBAL, &Globals.szLdapRootPassword,NULL, NULL, 0},
+#endif /* WITH_LDAP */
+
+
+ {"Miscellaneous Options", P_SEP, P_SEPARATOR},
+ {"smbrun", P_STRING, P_GLOBAL, &Globals.szSmbrun, 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},
+ {"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},
+ {"valid chars", P_STRING, P_GLOBAL, &Globals.szValidChars, handle_valid_chars, 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},
+ {"unix realname", P_BOOL, P_GLOBAL, &Globals.bUnixRealname, 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, 0},
+ {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, 0},
+ {"postexec", P_STRING, P_LOCAL, &sDefault.szPostExec, NULL, NULL, 0},
+ {"root preexec", P_STRING, P_LOCAL, &sDefault.szRootPreExec, NULL, NULL, 0},
+ {"root postexec", P_STRING, P_LOCAL, &sDefault.szRootPostExec, NULL, NULL, 0},
+ {"available", P_BOOL, P_LOCAL, &sDefault.bAvailable, NULL, NULL, 0},
+ {"volume", P_STRING, P_LOCAL, &sDefault.volume, NULL, NULL, 0},
+ {"fstype", P_STRING, P_LOCAL, &sDefault.fstype, NULL, NULL, 0},
+ {"set directory", P_BOOLREV, P_LOCAL, &sDefault.bNo_set_dir, NULL, NULL, 0},
+ {"wide links", P_BOOL, P_LOCAL, &sDefault.bWidelinks, NULL, NULL, FLAG_GLOBAL},
+ {"follow symlinks", P_BOOL, P_LOCAL, &sDefault.bSymlinks, NULL, NULL, FLAG_GLOBAL},
+ {"dont descend", P_STRING, P_LOCAL, &sDefault.szDontdescend, NULL, NULL, 0},
+ {"magic script", P_STRING, P_LOCAL, &sDefault.szMagicScript, NULL, NULL, 0},
+ {"magic output", P_STRING, P_LOCAL, &sDefault.szMagicOutput, NULL, NULL, 0},
+ {"delete readonly", P_BOOL, P_LOCAL, &sDefault.bDeleteReadonly, NULL, NULL, FLAG_GLOBAL},
+ {"dos filetimes", P_BOOL, P_LOCAL, &sDefault.bDosFiletimes, NULL, NULL, FLAG_GLOBAL},
+ {"dos filetime resolution",P_BOOL,P_LOCAL,&sDefault.bDosFiletimeResolution, NULL, NULL, FLAG_GLOBAL},
+
+ {"fake directory create times", P_BOOL,P_LOCAL, &sDefault.bFakeDirCreateTimes, NULL, NULL, FLAG_GLOBAL},
+ {"panic action", P_STRING, P_GLOBAL, &Globals.szPanicAction, NULL, NULL, 0},
+
+ {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
};
@@ -513,11 +775,14 @@ static void init_globals(void)
bzero((void *)&Globals,sizeof(Globals));
for (i = 0; parm_table[i].label; i++)
- if (parm_table[i].type == P_STRING &&
+ if ((parm_table[i].type == P_STRING ||
+ parm_table[i].type == P_USTRING) &&
parm_table[i].ptr)
string_init(parm_table[i].ptr,"");
string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
+ string_set(&sDefault.szPrinterDriver, "NULL");
+ string_set(&sDefault.fstype, FSTYPE_STRING);
done_init = True;
}
@@ -525,35 +790,44 @@ static void init_globals(void)
DEBUG(3,("Initialising global parameters\n"));
-#ifdef SMB_PASSWD_FILE
string_set(&Globals.szSMBPasswdFile, SMB_PASSWD_FILE);
-#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");
-#endif
string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
+ string_set(&Globals.szDriverFile, DRIVERFILE);
string_set(&Globals.szLockDir, LOCKDIR);
string_set(&Globals.szRootdir, "/");
- sprintf(s,"Samba %s",VERSION);
+ string_set(&Globals.szSmbrun, SMBRUN);
+ 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);
+
+ 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 host wins bcast");
+
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.max_xmit = 65535;
+ Globals.max_mux = 50; /* This is *needed* for profile support. */
Globals.lpqcachetime = 10;
Globals.pwordlevel = 0;
+ Globals.unamelevel = 0;
Globals.deadtime = 0;
Globals.max_log_size = 5000;
Globals.maxprotocol = PROTOCOL_NT1;
- Globals.security = SEC_SHARE;
+ Globals.security = SEC_USER;
Globals.bEncryptPasswords = False;
- Globals.printing = DEFAULT_PRINTING;
+ Globals.bUpdateEncrypt = False;
Globals.bReadRaw = True;
Globals.bWriteRaw = True;
Globals.bReadPrediction = False;
@@ -562,17 +836,96 @@ static void init_globals(void)
Globals.bStripDot = False;
Globals.syslog = 1;
Globals.bSyslogOnly = False;
+ Globals.bTimestampLogs = True;
Globals.os_level = 0;
- Globals.max_ttl = 60*60*4; /* 2 hours default */
- Globals.bPreferredMaster = True;
+ 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.shmem_size = SHMEM_SIZE;
+ Globals.stat_cache_size = 50; /* Number of stat translations we'll keep */
+ Globals.announce_as = ANNOUNCE_AS_NT;
+ Globals.bUnixRealname = False;
+#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.client_code_page = DEFAULT_CLIENT_CODE_PAGE;
+ Globals.bTimeServer = False;
+ Globals.bBindInterfacesOnly = False;
+ Globals.bNetWkstaUserLogon = False; /* This is now set to false by default as
+ the code in password.c protects us from this bug. */
+ Globals.bUnixPasswdSync = False;
+ Globals.bPasswdChatDebug = False;
+ Globals.bOleLockingCompat = True;
+ Globals.bNTSmbSupport = True; /* Do NT SMB's by default. */
+ Globals.bStatCache = True; /* use stat cache by default */
+
+#ifdef WITH_LDAP
+ /* default values for ldap */
+ string_set(&Globals.szLdapServer, "localhost");
+ Globals.ldap_port=389;
+#endif /* WITH_LDAP */
+
+#ifdef WITH_SSL
+ Globals.sslVersion = SMB_SSL_V23;
+ Globals.sslHostsRequire = NULL;
+ Globals.sslHostsResign = NULL;
+ Globals.sslCaCertDir = NULL;
+ Globals.sslCaCertFile = NULL;
+ Globals.sslCert = NULL;
+ Globals.sslPrivKey = NULL;
+ Globals.sslClientCert = NULL;
+ Globals.sslClientPrivKey = NULL;
+ Globals.sslCiphers = NULL;
+ 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.bPreferredMaster = False;
+ Globals.bLocalMaster = True;
Globals.bDomainMaster = False;
Globals.bDomainLogons = False;
Globals.bBrowseList = True;
+ Globals.bWINSsupport = False;
+ Globals.bWINSproxy = False;
-#ifdef KANJI
- coding_system = interpret_coding_system (KANJI, SJIS_CODE);
-#endif /* KANJI */
+ Globals.bDNSproxy = True;
+ /*
+ * smbd will check after starting to see if this value
+ * should be set to "true" or not.
+ */
+ lp_set_kernel_oplocks(False);
+
+ /*
+ * This must be done last as it checks the value in
+ * client_code_page.
+ */
+
+ interpret_coding_system(KANJI);
}
/***************************************************************************
@@ -591,10 +944,12 @@ Initialise the sDefault parameter structure.
static void init_locals(void)
{
/* choose defaults depending on the type of printing */
- switch (Globals.printing)
+ switch (sDefault.iPrinting)
{
case PRINT_BSD:
case PRINT_AIX:
+ case PRINT_LPRNG:
+ case PRINT_PLP:
string_initial(&sDefault.szLpqcommand,"lpq -P%p");
string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
@@ -605,10 +960,15 @@ static void init_locals(void)
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
+#ifdef SYSV
string_initial(&sDefault.szLppausecommand,"lp -i %p-%j -H hold");
string_initial(&sDefault.szLpresumecommand,"lp -i %p-%j -H resume");
-#endif
+ string_initial(&sDefault.szQueuepausecommand, "lpc stop %p");
+ string_initial(&sDefault.szQueueresumecommand, "lpc start %p");
+#else /* SYSV */
+ string_initial(&sDefault.szQueuepausecommand, "disable %p");
+ string_initial(&sDefault.szQueueresumecommand, "enable %p");
+#endif /* SYSV */
break;
case PRINT_QNX:
@@ -617,29 +977,63 @@ static void init_locals(void)
string_initial(&sDefault.szPrintcommand,"lp -r -P%p %s");
break;
+ case PRINT_SOFTQ:
+ string_initial(&sDefault.szLpqcommand,"qstat -l -d%p");
+ string_initial(&sDefault.szLprmcommand,"qstat -s -j%j -c");
+ string_initial(&sDefault.szPrintcommand,"lp -d%p -s %s; rm %s");
+ string_initial(&sDefault.szLppausecommand,"qstat -s -j%j -h");
+ string_initial(&sDefault.szLpresumecommand,"qstat -s -j%j -r");
+ break;
}
}
-/*******************************************************************
-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
+/******************************************************************* a
+convenience routine to grab string parameters into a rotating buffer,
+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(char *s)
{
- static pstring bufs[10];
- static int next=0;
+ static char *bufs[10];
+ static int buflen[10];
+ static int next = -1;
char *ret;
-
+ int i;
+ int len = s?strlen(s):0;
+
+ if (next == -1) {
+ /* initialisation */
+ for (i=0;i<10;i++) {
+ bufs[i] = NULL;
+ buflen[i] = 0;
+ }
+ next = 0;
+ }
+
+ len = MAX(len+100,sizeof(pstring)); /* the +100 is for some
+ substitution room */
+
+ if (buflen[next] != len) {
+ buflen[next] = len;
+ if (bufs[next]) free(bufs[next]);
+ bufs[next] = (char *)malloc(len);
+ if (!bufs[next]) {
+ DEBUG(0,("out of memory in lp_string()"));
+ exit(1);
+ }
+ }
+
ret = &bufs[next][0];
next = (next+1)%10;
if (!s)
*ret = 0;
else
- StrnCpy(ret,s,sizeof(pstring)-1);
+ StrCpy(ret,s);
+
+ trim_string(ret, "\"", "\"");
standard_sub_basic(ret);
return(ret);
@@ -670,6 +1064,7 @@ char *lp_string(char *s)
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_smbrun,&Globals.szSmbrun)
FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
@@ -678,24 +1073,75 @@ 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_name_resolve_order,&Globals.szNameResolveOrder)
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)
+#ifdef USING_GROUPNAME_MAP
+FN_GLOBAL_STRING(lp_groupname_map,&Globals.szGroupnameMap)
+#endif /* USING_GROUPNAME_MAP */
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,&Globals.szWINSserver)
+FN_GLOBAL_STRING(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_STRING(lp_netbios_aliases,&Globals.szNetbiosAliases)
+FN_GLOBAL_STRING(lp_driverfile,&Globals.szDriverFile)
+FN_GLOBAL_STRING(lp_panic_action,&Globals.szPanicAction)
+
+FN_GLOBAL_STRING(lp_domain_sid,&Globals.szDomainSID)
+FN_GLOBAL_STRING(lp_domain_groups,&Globals.szDomainGroups)
+FN_GLOBAL_STRING(lp_domain_admin_group,&Globals.szDomainAdminGroup)
+FN_GLOBAL_STRING(lp_domain_guest_group,&Globals.szDomainGuestGroup)
+FN_GLOBAL_STRING(lp_domain_admin_users,&Globals.szDomainAdminUsers)
+FN_GLOBAL_STRING(lp_domain_guest_users,&Globals.szDomainGuestUsers)
+
+#ifdef WITH_LDAP
+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_root,&Globals.szLdapRoot);
+FN_GLOBAL_STRING(lp_ldap_rootpasswd,&Globals.szLdapRootPassword);
+#endif /* WITH_LDAP */
+
+#ifdef WITH_SSL
+FN_GLOBAL_INTEGER(lp_ssl_version,&Globals.sslVersion);
+FN_GLOBAL_STRING(lp_ssl_hosts,&Globals.sslHostsRequire);
+FN_GLOBAL_STRING(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_cert,&Globals.sslCert);
+FN_GLOBAL_STRING(lp_ssl_privkey,&Globals.sslPrivKey);
+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_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_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_controller,&Globals.bDomainController)
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)
@@ -703,25 +1149,50 @@ 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_update_encrypted,&Globals.bUpdateEncrypt)
FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
+FN_GLOBAL_BOOL(lp_timestamp_logs,&Globals.bTimestampLogs)
FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
+FN_GLOBAL_BOOL(lp_unix_realname,&Globals.bUnixRealname)
+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_net_wksta_user_logon,&Globals.bNetWkstaUserLogon)
+FN_GLOBAL_BOOL(lp_unix_password_sync,&Globals.bUnixPasswdSync)
+FN_GLOBAL_BOOL(lp_passwd_chat_debug,&Globals.bPasswdChatDebug)
+FN_GLOBAL_BOOL(lp_ole_locking_compat,&Globals.bOleLockingCompat)
+FN_GLOBAL_BOOL(lp_nt_smb_support,&Globals.bNTSmbSupport)
+FN_GLOBAL_BOOL(lp_stat_cache,&Globals.bStatCache)
+FN_GLOBAL_BOOL(lp_kernel_oplocks,&Globals.bKernelOplocks)
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.max_wins_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_usernamelevel,&Globals.unamelevel)
+FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
+FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size)
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_GLOBAL_INTEGER(lp_client_code_page,&Globals.client_code_page)
+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)
+
+#ifdef WITH_LDAP
+FN_GLOBAL_INTEGER(lp_ldap_port,&Globals.ldap_port)
+#endif /* WITH_LDAP */
FN_LOCAL_STRING(lp_preexec,szPreExec)
FN_LOCAL_STRING(lp_postexec,szPostExec)
@@ -740,7 +1211,10 @@ 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)
FN_LOCAL_STRING(lp_printername,szPrintername)
+FN_LOCAL_STRING(lp_printerdriver,szPrinterDriver)
FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
FN_LOCAL_STRING(lp_magicscript,szMagicScript)
@@ -750,10 +1224,14 @@ 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_fstype,fstype)
+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_alternate_permissions,bAlternatePerm)
FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
FN_LOCAL_BOOL(lp_casesensitive,bCaseSensitive)
FN_LOCAL_BOOL(lp_preservecase,bCasePreserve)
@@ -773,16 +1251,30 @@ 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_oplocks,bOpLocks)
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_sync,bStrictSync)
FN_LOCAL_BOOL(lp_map_system,bMap_system)
-
-FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
+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_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_INTEGER(lp_create_mode,iCreate_mask)
+FN_LOCAL_INTEGER(lp_force_create_mode,iCreate_force_mode)
+FN_LOCAL_INTEGER(lp_dir_mode,iDir_mask)
+FN_LOCAL_INTEGER(lp_force_dir_mode,iDir_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_printing,iPrinting)
FN_LOCAL_CHAR(lp_magicchar,magic_char)
@@ -799,8 +1291,6 @@ static void copy_service( service *pserviceDest,
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);
@@ -823,8 +1313,20 @@ static void free_service(service *pservice)
if (!pservice)
return;
+ if(pservice->szService)
+ DEBUG(5,("free_service: Freeing service %s\n", pservice->szService));
+
+ string_free(&pservice->szService);
+ if (pservice->copymap)
+ {
+ free(pservice->copymap);
+ pservice->copymap = NULL;
+ }
+
for (i=0;parm_table[i].label;i++)
- if (parm_table[i].type == P_STRING && parm_table[i].class == P_LOCAL)
+ 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)));
}
@@ -894,7 +1396,8 @@ BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir)
if (!(*(iSERVICE(i).comment)))
{
pstring comment;
- sprintf(comment,"Home directory of %s",pszHomename);
+ slprintf(comment,sizeof(comment)-1,
+ "Home directory of %s",pszHomename);
string_set(&iSERVICE(i).comment,comment);
}
iSERVICE(i).bAvailable = sDefault.bAvailable;
@@ -925,9 +1428,10 @@ static BOOL lp_add_ipc(void)
if (i < 0)
return(False);
- sprintf(comment,"IPC Service (%s)",lp_serverstring());
+ slprintf(comment,sizeof(comment)-1,
+ "IPC Service (%s)", Globals.szServerString );
- string_set(&iSERVICE(i).szPath,"/tmp");
+ string_set(&iSERVICE(i).szPath,tmpdir());
string_set(&iSERVICE(i).szUsername,"");
string_set(&iSERVICE(i).comment,comment);
iSERVICE(i).status = False;
@@ -965,6 +1469,14 @@ BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
string_set(&iSERVICE(i).szPrintername,pszPrintername);
string_set(&iSERVICE(i).comment,comment);
iSERVICE(i).bBrowseable = sDefault.bBrowseable;
+ /* Printers cannot be read_only. */
+ iSERVICE(i).bRead_only = False;
+ /* No share modes on printer services. */
+ iSERVICE(i).bShareModes = False;
+ /* No oplocks on printer services. */
+ iSERVICE(i).bOpLocks = False;
+ /* Printer services must be printable. */
+ iSERVICE(i).bPrint_ok = True;
DEBUG(3,("adding printer service %s\n",pszPrintername));
@@ -1044,7 +1556,7 @@ static BOOL set_boolean(BOOL *pb, char *pszParmValue)
*pb = False;
else
{
- DEBUG(0,( "Badly formed boolean in configuration file: \"%s\".\n",
+ DEBUG(0,("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
pszParmValue));
bRetval = False;
}
@@ -1102,6 +1614,7 @@ static void copy_service(service *pserviceDest,
break;
case P_INTEGER:
+ case P_ENUM:
case P_OCTAL:
*(int *)dest_ptr = *(int *)src_ptr;
break;
@@ -1113,6 +1626,11 @@ static void copy_service(service *pserviceDest,
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;
default:
break;
}
@@ -1156,8 +1674,8 @@ static BOOL service_ok(int iService)
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");
+ DEBUG(0,("No path in service %s - using %s\n",iSERVICE(iService).szService,tmpdir()));
+ string_set(&iSERVICE(iService).szPath,tmpdir());
}
/* If a service is flagged unavailable, log the fact at level 0. */
@@ -1201,7 +1719,7 @@ static void add_to_file_list(char *fname)
{
pstring n2;
- strcpy(n2,fname);
+ pstrcpy(n2,fname);
standard_sub_basic(n2);
f->modtime = file_modtime(n2);
}
@@ -1214,85 +1732,51 @@ check if a config file has changed date
BOOL lp_file_list_changed(void)
{
struct file_lists *f = file_lists;
- while (f) {
+ DEBUG(6,("lp_file_list_changed()\n"));
+
+ while (f)
+ {
pstring n2;
- strcpy(n2,f->name);
+ time_t mod_time;
+
+ pstrcpy(n2,f->name);
standard_sub_basic(n2);
- if (f->modtime != file_modtime(n2)) return(True);
- f = f->next;
+
+ 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) {
+ DEBUGADD(6,("file %s modified: %s\n", n2, ctime(&mod_time)));
+ f->modtime = mod_time;
+ 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)
+static BOOL handle_coding_system(char *pszParmValue,char **ptr)
{
- *val = interpret_coding_system(pszParmValue,*val);
- return(True);
+ string_set(ptr,pszParmValue);
+ interpret_coding_system(pszParmValue);
+ return(True);
}
-#endif /* KANJI */
/***************************************************************************
handle the interpretation of the character set system parameter
***************************************************************************/
-static BOOL handle_character_set(char *pszParmValue,int *val)
-{
- string_set(&Globals.szCharacterSet,pszParmValue);
- *val = interpret_character_set(pszParmValue,*val);
- return(True);
-}
-
-
-/***************************************************************************
-handle the interpretation of the protocol parameter
-***************************************************************************/
-static BOOL handle_protocol(char *pszParmValue,int *val)
-{
- *val = interpret_protocol(pszParmValue,*val);
- return(True);
-}
-
-/***************************************************************************
-handle the interpretation of the security parameter
-***************************************************************************/
-static BOOL handle_security(char *pszParmValue,int *val)
-{
- *val = interpret_security(pszParmValue,*val);
- return(True);
-}
-
-/***************************************************************************
-handle the interpretation of the default case
-***************************************************************************/
-static BOOL handle_case(char *pszParmValue,int *val)
+static BOOL handle_character_set(char *pszParmValue,char **ptr)
{
- if (strequal(pszParmValue,"LOWER"))
- *val = CASE_LOWER;
- else if (strequal(pszParmValue,"UPPER"))
- *val = CASE_UPPER;
- return(True);
+ string_set(ptr,pszParmValue);
+ interpret_character_set(pszParmValue);
+ return(True);
}
-/***************************************************************************
-handle the interpretation of the printing system
-***************************************************************************/
-static BOOL handle_printing(char *pszParmValue,int *val)
-{
- 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);
-}
/***************************************************************************
handle the valid chars lines
@@ -1301,6 +1785,12 @@ static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
{
string_set(ptr,pszParmValue);
+ /* A dependency here is that the parameter client code page must be
+ set before this is called - as calling codepage_initialise()
+ would overwrite the valid char lines.
+ */
+ codepage_initialise(lp_client_code_page());
+
add_char_string(pszParmValue);
return(True);
}
@@ -1312,7 +1802,7 @@ handle the include operation
static BOOL handle_include(char *pszParmValue,char **ptr)
{
pstring fname;
- strcpy(fname,pszParmValue);
+ pstrcpy(fname,pszParmValue);
add_to_file_list(fname);
@@ -1390,18 +1880,24 @@ static void init_copymap(service *pservice)
/***************************************************************************
-Process a parameter.
+ return the local pointer to a parameter given the service number and the
+ pointer into the default structure
***************************************************************************/
-static BOOL do_parameter(char *pszParmName, char *pszParmValue)
+void *lp_local_ptr(int snum, void *ptr)
{
- int parmnum;
+ return (void *)(((char *)pSERVICE(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;
- if (!bInGlobalSection && bGlobalOnly) return(True);
-
- DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
-
parmnum = map_parameter(pszParmName);
if (parmnum < 0)
@@ -1410,40 +1906,40 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)
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 (bInGlobalSection)
+ if (snum < 0) {
parm_ptr = def_ptr;
- else
- {
- if (parm_table[parmnum].class == P_GLOBAL)
- {
+ } 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);
- }
+ parm_ptr = ((char *)pSERVICE(snum)) + 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 (snum >= 0) {
+ if (!iSERVICE(snum).copymap)
+ init_copymap(pSERVICE(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)
+ iSERVICE(snum).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);
- }
+ 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)
@@ -1473,51 +1969,101 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)
string_set(parm_ptr,pszParmValue);
break;
+ case P_USTRING:
+ string_set(parm_ptr,pszParmValue);
+ strupper(*(char **)parm_ptr);
+ break;
+
case P_GSTRING:
- strcpy((char *)parm_ptr,pszParmValue);
+ 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 )
+{
+ if( !bInGlobalSection && bGlobalOnly )
+ return(True);
+
+ DEBUGADD( 3, ( "doing parameter %s = %s\n", pszParmName, pszParmValue ) );
+
+ 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)
+static void print_parameter(struct parm_struct *p,void *ptr, FILE *f)
{
- switch (type)
- {
- case P_BOOL:
- printf("%s",BOOLSTR(*(BOOL *)ptr));
- break;
+ 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:
- printf("%s",BOOLSTR(! *(BOOL *)ptr));
- break;
+ case P_BOOLREV:
+ fprintf(f,"%s",BOOLSTR(! *(BOOL *)ptr));
+ break;
- case P_INTEGER:
- printf("%d",*(int *)ptr);
- break;
+ case P_INTEGER:
+ fprintf(f,"%d",*(int *)ptr);
+ break;
- case P_CHAR:
- printf("%c",*(char *)ptr);
- break;
+ case P_CHAR:
+ fprintf(f,"%c",*(char *)ptr);
+ break;
- case P_OCTAL:
- printf("0%o",*(int *)ptr);
- break;
+ case P_OCTAL:
+ fprintf(f,"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;
- }
+ 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;
+ }
}
@@ -1533,6 +2079,7 @@ static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
case P_INTEGER:
+ case P_ENUM:
case P_OCTAL:
return(*((int *)ptr1) == *((int *)ptr2));
@@ -1540,6 +2087,7 @@ static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
return(*((char *)ptr1) == *((char *)ptr2));
case P_GSTRING:
+ case P_UGSTRING:
{
char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
if (p1 && !*p1) p1 = NULL;
@@ -1547,12 +2095,15 @@ static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
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);
}
@@ -1579,7 +2130,7 @@ static BOOL do_section(char *pszSectionName)
/* check for multiple global sections */
if (bInGlobalSection)
{
- DEBUG(3,( "Processing section \"[%s]\"\n", pszSectionName));
+ DEBUG( 3, ( "Processing section \"[%s]\"\n", pszSectionName ) );
return(True);
}
@@ -1608,56 +2159,150 @@ static BOOL do_section(char *pszSectionName)
return (bRetval);
}
+
+/***************************************************************************
+determine if a partcular base parameter is currently set to the default value.
+***************************************************************************/
+static BOOL is_default(int i)
+{
+ if (!defaults_saved) return False;
+ switch (parm_table[i].type) {
+ 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;
- printf("Global parameters:\n");
+ int i;
+ fprintf(f, "# Global parameters\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");
+ }
+}
- 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 True if a local parameter is currently set to the global default
+***************************************************************************/
+BOOL lp_is_default(int snum, struct parm_struct *parm)
+{
+ int pdiff = PTR_DIFF(parm->ptr,&sDefault);
+
+ return equal_parameter(parm->type,
+ ((char *)pSERVICE(snum)) + pdiff,
+ ((char *)&sDefault) + pdiff);
}
+
/***************************************************************************
Display the contents of a single services record.
***************************************************************************/
-static void dump_a_service(service *pService)
+static void dump_a_service(service *pService, FILE *f)
{
- int i;
- if (pService == &sDefault)
- printf("\nDefault service parameters:\n");
- else
- printf("\nService parameters [%s]:\n",pService->szService);
+ 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");
+ }
+}
- 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");
- }
- }
+/***************************************************************************
+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 = pSERVICE(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.
@@ -1689,66 +2334,46 @@ BOOL lp_snum_ok(int iService)
/***************************************************************************
-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);
-
- if (!str)
- 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);
-
- if (lp_servicenumber(p) >= 0) continue;
-
- if (home && homes >= 0)
- {
- lp_add_home(p,homes,home);
- continue;
+ char *s;
+ char *p;
+ int homes;
+
+ if (!str) return;
+
+ s = strdup(str);
+ if (!s) return;
+
+ homes = lp_servicenumber(HOMES_NAME);
+
+ for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP)) {
+ char *home = get_home_dir(p);
+
+ if (lp_servicenumber(p) >= 0) continue;
+
+ if (home && homes >= 0) {
+ lp_add_home(p,homes,home);
+ }
}
-
- if (printers >= 0 && pcap_printername_ok(p,NULL))
- lp_add_printer(p,printers);
- }
- free(s);
+ free(s);
}
/***************************************************************************
auto-load one printer
***************************************************************************/
-static void lp_add_one_printer(char *name,char *comment)
-{
- 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);
- }
-}
-
-
-/***************************************************************************
-auto-load printer services
-***************************************************************************/
-static void lp_add_all_printers(void)
+void lp_add_one_printer(char *name,char *comment)
{
- int printers = lp_servicenumber(PRINTERS_NAME);
-
- if (printers < 0) return;
+ int printers = lp_servicenumber(PRINTERS_NAME);
+ int i;
- pcap_printer_fn(lp_add_one_printer);
+ if (lp_servicenumber(name) < 0) {
+ lp_add_printer(name,printers);
+ if ((i=lp_servicenumber(name)) >= 0)
+ string_set(&iSERVICE(i).comment,comment);
+ }
}
/***************************************************************************
@@ -1766,22 +2391,62 @@ void lp_killunused(BOOL (*snumused)(int ))
{
int i;
for (i=0;i<iNumServices;i++)
- if (VALID(i) && !snumused(i))
+ if (VALID(i) && (!snumused || !snumused(i)))
{
iSERVICE(i).valid = False;
free_service(pSERVICE(i));
}
}
+
+/***************************************************************************
+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.
+***************************************************************************/
+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_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;
+}
+
+
/***************************************************************************
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);
bRetval = False;
@@ -1790,8 +2455,13 @@ BOOL lp_load(char *pszFname,BOOL global_only)
bGlobalOnly = global_only;
init_globals();
+
+ if (save_defaults) {
+ init_locals();
+ lp_save_defaults();
+ }
- strcpy(n2,pszFname);
+ pstrcpy(n2,pszFname);
standard_sub_basic(n2);
/* We get sections first, so have to start 'behind' to make up */
@@ -1805,10 +2475,20 @@ BOOL lp_load(char *pszFname,BOOL global_only)
bRetval = service_ok(iServiceIndex);
lp_add_auto_services(lp_auto_services());
- if (lp_load_printers())
- lp_add_all_printers();
- lp_add_ipc();
+ if (add_ipc)
+ lp_add_ipc();
+
+ set_default_server_announce_type();
+
+ /* We set a WINS server address of 127.0.0.1 if we are in the client */
+ /* and we have WINS support enabled */
+
+ if (in_client && Globals.bWINSsupport) {
+
+ string_set(&Globals.szWINSserver, "127.0.0.1");
+
+ }
bLoaded = True;
@@ -1827,13 +2507,17 @@ int lp_numservices(void)
/***************************************************************************
Display the contents of the services array in human-readable form.
***************************************************************************/
-void lp_dump(void)
+void lp_dump(FILE *f, BOOL show_defaults)
{
int iService;
- dump_globals();
+ if (show_defaults) {
+ defaults_saved = False;
+ }
+
+ dump_globals(f);
- dump_a_service(&sDefault);
+ dump_a_service(&sDefault, f);
for (iService = 0; iService < iNumServices; iService++)
{
@@ -1841,11 +2525,12 @@ void lp_dump(void)
{
if (iSERVICE(iService).szService[0] == '\0')
break;
- dump_a_service(pSERVICE(iService));
+ dump_a_service(pSERVICE(iService), 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
@@ -1858,7 +2543,7 @@ int lp_servicenumber(char *pszServiceName)
for (iService = iNumServices - 1; iService >= 0; iService--)
if (VALID(iService) &&
- strwicmp(iSERVICE(iService).szService, pszServiceName) == 0)
+ strequal(lp_servicename(iService), pszServiceName))
break;
if (iService < 0)
@@ -1867,25 +2552,126 @@ int lp_servicenumber(char *pszServiceName)
return (iService);
}
+/*******************************************************************
+ a useful volume label function
+ ******************************************************************/
+char *volume_label(int snum)
+{
+ char *ret = lp_volume(snum);
+ if (!*ret) return(lp_servicename(snum));
+ return(ret);
+}
+
+/*******************************************************************
+ Set the server type we will announce as via nmbd.
+********************************************************************/
+static void set_default_server_announce_type(void)
+{
+ default_server_announce = (SV_TYPE_WORKSTATION | SV_TYPE_SERVER |
+ SV_TYPE_SERVER_UNIX | SV_TYPE_PRINTQ_SERVER);
+ if(lp_announce_as() == ANNOUNCE_AS_NT)
+ default_server_announce |= (SV_TYPE_SERVER_NT | SV_TYPE_NT);
+ else if(lp_announce_as() == ANNOUNCE_AS_WIN95)
+ default_server_announce |= SV_TYPE_WIN95_PLUS;
+ else if(lp_announce_as() == ANNOUNCE_AS_WFW)
+ default_server_announce |= SV_TYPE_WFW;
+ default_server_announce |= (lp_time_server() ? SV_TYPE_TIME_SOURCE : 0);
+}
/*******************************************************************
- get a workgroup - but map to standalone if '*'
- ******************************************************************/
-char *my_workgroup(void)
+remove a service
+********************************************************************/
+void lp_remove_service(int snum)
{
- char *res = lp_workgroup();
- if (*res == '*') return("STANDALONE");
- return(res);
+ pSERVICE(snum)->valid = False;
}
/*******************************************************************
- a useful volume label function
- ******************************************************************/
-char *volume_label(int snum)
+copy a service
+********************************************************************/
+void lp_copy_service(int snum, char *new_name)
{
- char *ret = lp_volume(snum);
- if (!*ret) return(lp_servicename(snum));
- return(ret);
+ 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(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(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;
+}
+
+/***********************************************************
+ Set the real value of kernel oplocks (called by smbd).
+************************************************************/
+
+void lp_set_kernel_oplocks(BOOL val)
+{
+ Globals.bKernelOplocks = val;
}
diff --git a/source/param/params.c b/source/param/params.c
index b9d61382a18..2a0a253f208 100644
--- a/source/param/params.c
+++ b/source/param/params.c
@@ -1,335 +1,569 @@
-/*
- 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"
+/* -------------------------------------------------------------------------- **
+ * 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>.
+ */
-/* 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)
-{
- 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)
+static char *bufr = NULL;
+static int bSize = 0;
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+static int EatWhitespace( FILE *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 = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) )
+ ;
+ return( c );
+ } /* EatWhitespace */
+
+static int EatComment( FILE *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 = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) )
+ ;
+ return( c );
+ } /* EatComment */
+
+static int Continuation( char *line, int pos )
+ /* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ pos--;
+ while( (pos >= 0) && isspace(line[pos]) )
+ pos--;
+
+ return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 );
+ } /* Continuation */
+
+
+static BOOL Section( FILE *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) )
{
- /* 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;
- }
+ bSize += BUFR_INC;
+ bufr = Realloc( bufr, bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
}
- }
- return (bRetval);
-}
-
-
-/***********************************************************************
-Close up s by n chars, at offset start.
-***********************************************************************/
-static void closestr(char *s, int start, int n)
-{
- char *src;
- char *dest;
- int len;
-
- if (n > 0)
- if ((src = dest = s) != NULL)
+
+ /* Handle a single character. */
+ switch( c )
{
- len = strlen(s);
- if (start >= 0 && start < len - n)
- {
- src += start + n;
- dest += start;
-
- while (*src)
- *dest++ = *src++;
- *dest = '\0';
- }
+ 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 = getc( 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 = getc( InFile );
+ }
}
-}
-
-/**************************************************************************
-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)
+ }
+
+ /* 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( FILE *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. */
{
- /* stop - return OK unless file error */
- bRetval = !ferror(fileIn);
- if (!bRetval)
- DEBUG(0,( "Read error on configuration file (enumerating sections)!\n"));
- break;
+ bSize += BUFR_INC;
+ bufr = Realloc( bufr, bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
}
- else
+
+ switch( c )
{
- 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;
- }
- }
+ 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 = getc( 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 = getc( InFile );
+ }
}
- }
-
- 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;
+ }
- /* 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);
+ bSize += BUFR_INC;
+ bufr = Realloc( bufr, bSize );
+ if( NULL == bufr )
+ {
+ DEBUG(0, ("%s Memory re-allocation failure.", func) );
+ return( False );
+ }
}
- if (!bRetval)
- DEBUG(0,("pm_process retuned false\n"));
- return (bRetval);
-}
-
-
-/**************************************************************************
-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';
- }
-}
-
-/**************************************************************************
-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';
- }
-}
-
-/***********************************************************************
-Collapse each whitespace area in a string to a single space.
-***********************************************************************/
-static void collapse_spaces(char *psz)
-{
- while (*psz)
- if (isspace(*psz))
+ switch( c )
{
- *psz++ = ' ';
- trimleft(psz);
+ case '\r': /* Explicitly remove '\r' because the older */
+ c = getc( 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(bufr[end]); end-- )
+ ;
+ c = getc( 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 = getc( InFile );
+ break;
}
- else
- psz++;
-}
-
-/**************************************************************************
-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);
-}
+ }
+ bufr[end] = '\0'; /* End of value. */
+
+ return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */
+ } /* Parameter */
+
+static BOOL Parse( FILE *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 FILE *OpenConfFile( char *FileName )
+ /* ------------------------------------------------------------------------ **
+ * Open a configuration file.
+ *
+ * Input: FileName - The pathname of the config file to be opened.
+ *
+ * Output: A pointer of type (FILE *) to the opened file, or NULL if the
+ * file could not be opened.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ FILE *OpenedFile;
+ char *func = "params.c:OpenConfFile() -";
+
+ if( NULL == FileName || 0 == *FileName )
+ {
+ DEBUG( 0, ("%s No configuration filename specified.\n", func) );
+ return( NULL );
+ }
+
+ OpenedFile = fopen( FileName, "r" );
+ if( NULL == OpenedFile )
+ {
+ DEBUG( 0,
+ ("%s Unable to open configuration file \"%s\":\n\t%s\n",
+ func, FileName, strerror(errno)) );
+ }
+
+ return( OpenedFile );
+ } /* 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;
+ FILE *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));
+ fclose(InFile);
+ return( False );
+ }
+ result = Parse( InFile, sfunc, pfunc );
+ free( bufr );
+ bufr = NULL;
+ bSize = 0;
+ }
+
+ fclose(InFile);
+
+ if( !result ) /* Generic failure. */
+ {
+ DEBUG(0,("%s Failed. Error returned from params.c:parse().\n", func));
+ return( False );
+ }
+
+ return( True ); /* Generic success. */
+ } /* pm_process */
+
+/* -------------------------------------------------------------------------- */
diff --git a/source/parsing.doc b/source/parsing.doc
new file mode 100644
index 00000000000..d024a22a515
--- /dev/null
+++ b/source/parsing.doc
@@ -0,0 +1,181 @@
+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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/passdb/ldap.c b/source/passdb/ldap.c
new file mode 100644
index 00000000000..59c6cd3d4ff
--- /dev/null
+++ b/source/passdb/ldap.c
@@ -0,0 +1,997 @@
+/*
+ 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
+
+extern int DEBUGLEVEL;
+
+/*******************************************************************
+ 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, char *user, 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, 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());
+ string_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;
+
+ snprintf(filter, sizeof(pstring), "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);
+
+ bzero(smblmpwd, sizeof(smblmpwd));
+ bzero(smbntpwd, 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);
+ bzero(temp, sizeof(temp)); /* destroy local copy of the password */
+#else
+ get_single_attribute(ldap_struct, entry, "unicodePwd", temp);
+ pdb_gethexpwd(temp, smbntpwd);
+ bzero(temp, sizeof(temp)); /* destroy local copy of the password */
+
+ get_single_attribute(ldap_struct, entry, "dBCSPwd", temp);
+ pdb_gethexpwd(temp, smblmpwd);
+ bzero(temp, 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 = 0x00020000; /* don't know */
+ user->unknown_5 = 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, char *attribute, char *value)
+{
+ LDAPMod **mods;
+ int i;
+ int j;
+
+ mods = *modlist;
+
+ if (mods == NULL)
+ {
+ mods = (LDAPMod **)malloc( sizeof(LDAPMod *) );
+ 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 * ) );
+ mods[i] = (LDAPMod *)malloc( sizeof( LDAPMod ) );
+ 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 * ));
+ 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", pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ 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", pdb_encode_acct_ctrl(newpwd->acct_ctrl,NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+ 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 *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 struct sam_disp_info *getldapdispnam(char *name)
+{
+ return pdb_sam_to_dispinfo(getldap21pwnam(name));
+}
+
+static struct sam_disp_info *getldapdisprid(uint32 rid)
+{
+ return pdb_sam_to_dispinfo(getldap21pwrid(rid));
+}
+
+static struct sam_disp_info *getldapdispent(void *vp)
+{
+ return pdb_sam_to_dispinfo(getldap21pwent(vp));
+}
+
+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,
+ getldappwent,
+ add_ldappwd_entry,
+ mod_ldappwd_entry,
+ getldap21pwent,
+ iterate_getsam21pwnam, /* From passdb.c */
+ iterate_getsam21pwuid, /* From passdb.c */
+ iterate_getsam21pwrid, /* From passdb.c */
+ add_ldap21pwd_entry,
+ mod_ldap21pwd_entry,
+ getldapdispnam,
+ getldapdisprid,
+ getldapdispent
+};
+
+struct passdb_ops *ldap_initialize_password_db(void)
+{
+ return &ldap_ops;
+}
+
+#else
+ void dummy_function(void) { } /* stop some compilers complaining */
+#endif
diff --git a/source/passdb/nispass.c b/source/passdb/nispass.c
new file mode 100644
index 00000000000..4a2a7723d64
--- /dev/null
+++ b/source/passdb/nispass.c
@@ -0,0 +1,697 @@
+/*
+ * 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.
+ */
+
+#ifdef WITH_NISPLUS
+
+#include "includes.h"
+#include <rpcsvc/nis.h>
+
+extern int DEBUGLEVEL;
+
+static int 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, len, ENTRY_VAL(new_obj, col));
+}
+
+/***************************************************************
+ 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)
+{
+}
+
+/*************************************************************************
+ Routine to return the next entry in the nisplus passwd list.
+ this function is a nice, messy combination of reading:
+ - the nisplus passwd file
+ - the unix password database
+ - nisp.conf options (not done at present).
+
+ do not call this function directly. use passdb.c instead.
+
+ *************************************************************************/
+static struct sam_passwd *getnisp21pwent(void *vp)
+{
+ return 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)
+{
+ return (SMB_BIG_UINT)0;
+}
+
+/*************************************************************************
+ 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)
+{
+ return False;
+}
+
+/*************************************************************************
+ sets a NIS+ attribute
+ *************************************************************************/
+static void set_single_attribute(nis_object *new_obj, int col,
+ char *val, int len, int flags)
+{
+ if (new_obj == NULL) return;
+
+ ENTRY_VAL(new_obj, col) = val;
+ ENTRY_LEN(new_obj, col) = len;
+
+ 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;
+
+ bzero(logon_t , sizeof(logon_t ));
+ bzero(logoff_t , sizeof(logoff_t ));
+ bzero(kickoff_t, sizeof(kickoff_t));
+ bzero(pwdlset_t, sizeof(pwdlset_t));
+ bzero(pwdlchg_t, sizeof(pwdlchg_t));
+ bzero(pwdmchg_t, 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_nisppwd_entry: nis_list failure: %s: %s\n",
+ nisname, nis_sperrno(result->status)));
+ nis_freeresult(nis_user);
+ nis_freeresult(result);
+ return False;
+ }
+
+ if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
+ {
+ DEBUG(3, ("add_nisppwd_entry: User already exists in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ nis_freeresult(nis_user);
+ return False;
+ }
+
+#if 0
+ /* User not found. */
+ if (!add_user)
+ {
+ DEBUG(3, ("add_nisppwd_entry: User not found in NIS+ password db: %s\n",
+ pfile));
+ nis_freeresult(result);
+ nis_freeresult(nis_user);
+ return False;
+ }
+
+#endif
+
+ tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
+ if (tblresult->status != NIS_SUCCESS)
+ {
+ nis_freeresult(result);
+ nis_freeresult(nis_user);
+ nis_freeresult(tblresult);
+ DEBUG(3, ( "add_nisppwd_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));
+
+ pdb_sethexpwd(smb_passwd , newpwd->smb_passwd , newpwd->acct_ctrl);
+ pdb_sethexpwd(smb_nt_passwd, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+
+ pdb_set_logon_time (logon_t , sizeof(logon_t ), newpwd->logon_time );
+ pdb_set_logoff_time (logoff_t , sizeof(logoff_t ), newpwd->logoff_time );
+ pdb_set_kickoff_time (kickoff_t, sizeof(kickoff_t), newpwd->kickoff_time );
+ pdb_set_last_set_time (pwdlset_t, sizeof(pwdlset_t), newpwd->pass_last_set_time );
+ pdb_set_can_change_time (pwdlchg_t, sizeof(pwdlchg_t), newpwd->pass_can_change_time );
+ pdb_set_must_change_time(pwdmchg_t, sizeof(pwdmchg_t), newpwd->pass_must_change_time);
+
+ slprintf(uid, sizeof(uid), "%u", newpwd->smb_userid);
+ slprintf(user_rid, sizeof(user_rid), "0x%x", newpwd->user_rid);
+ slprintf(smb_grpid, sizeof(smb_grpid), "%u", newpwd->smb_grpid);
+ slprintf(group_rid, sizeof(group_rid), "0x%x", newpwd->group_rid);
+
+ safe_strcpy(acb, pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), sizeof(acb));
+
+ 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);
+ 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);
+
+ obj = &new_obj;
+
+ addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
+
+ nis_freeresult(nis_user);
+ if (tblresult)
+ {
+ nis_freeresult(tblresult);
+ }
+
+ if (addresult->status != NIS_SUCCESS)
+ {
+ DEBUG(3, ( "add_nisppwd_entry: NIS+ table update failed: %s\n",
+ nisname, nis_sperrno(addresult->status)));
+ nis_freeresult(addresult);
+ nis_freeresult(result);
+ return False;
+ }
+
+ 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)
+{
+ return False;
+}
+
+/************************************************************************
+ makes a struct sam_passwd from a NIS+ result.
+ ************************************************************************/
+static BOOL make_sam_from_nisp(struct sam_passwd *pw_buf, nis_result *result)
+{
+ int uidval;
+ static pstring user_name;
+ static unsigned char smbpwd[16];
+ static unsigned char smbntpwd[16];
+ nis_object *obj;
+ uchar *p;
+
+ if (pw_buf == NULL || result == NULL) return False;
+
+ pdb_init_sam(pw_buf);
+
+ if (result->status != NIS_SUCCESS)
+ {
+ DEBUG(0, ("make_smb_from_nisp: NIS+ lookup failure: %s\n",
+ nis_sperrno(result->status)));
+ return False;
+ }
+
+ /* User not found. */
+ if (NIS_RES_NUMOBJ(result) <= 0)
+ {
+ DEBUG(10, ("make_smb_from_nisp: user not found in NIS+\n"));
+ return False;
+ }
+
+ if (NIS_RES_NUMOBJ(result) > 1)
+ {
+ DEBUG(10, ("make_smb_from_nisp: WARNING: Multiple entries for user in NIS+ table!\n"));
+ }
+
+ /* Grab the first hit. */
+ obj = &NIS_RES_OBJECT(result)[0];
+
+ /* Check the lanman password column. */
+ p = (uchar *)ENTRY_VAL(obj, NPF_LMPWD);
+ if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbpwd))
+ {
+ DEBUG(0, ("make_smb_from_nisp: malformed LM pwd entry.\n"));
+ return False;
+ }
+
+ /* Check the NT password column. */
+ p = (uchar *)ENTRY_VAL(obj, NPF_NTPWD);
+ if (strlen((char *)p) != 32 || !pdb_gethexpwd((char *)p, (char *)smbntpwd))
+ {
+ DEBUG(0, ("make_smb_from_nisp: malformed NT pwd entry\n"));
+ return False;
+ }
+
+ strncpy(user_name, ENTRY_VAL(obj, NPF_NAME), sizeof(user_name));
+ uidval = atoi(ENTRY_VAL(obj, NPF_UID));
+
+ pw_buf->smb_name = user_name;
+ pw_buf->smb_userid = uidval;
+ pw_buf->smb_passwd = smbpwd;
+ pw_buf->smb_nt_passwd = smbntpwd;
+
+ 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, ("getnisppwnam: search by name: %s\n", name));
+ DEBUG(10, ("getnisppwnam: 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,("getnisppwnam: NIS+ lookup time out\n"));
+ nis_freeresult(result);
+ return NULL;
+ }
+
+ ret = make_sam_from_nisp(&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, ("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_nisp(&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 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 *getnisppwuid(uid_t smb_userid)
+{
+ return pdb_sam_to_smb(getnisp21pwuid(smb_userid));
+}
+
+static struct sam_disp_info *getnispdispnam(char *name)
+{
+ return pdb_sam_to_dispinfo(getnisp21pwnam(name));
+}
+
+static struct sam_disp_info *getnispdisprid(uint32 rid)
+{
+ return pdb_sam_to_dispinfo(getnisp21pwrid(rid));
+}
+
+static struct sam_disp_info *getnispdispent(void *vp)
+{
+ return pdb_sam_to_dispinfo(getnisp21pwent(vp));
+}
+
+static struct passdb_ops nispasswd_ops = {
+ startnisppwent,
+ endnisppwent,
+ getnisppwpos,
+ setnisppwpos,
+ getnisppwnam,
+ getnisppwuid,
+ getnisppwent,
+ add_nisppwd_entry,
+ mod_nisppwd_entry,
+ getnisp21pwent,
+ getnisp21pwnam,
+ getnisp21pwuid,
+ getnisp21pwrid,
+ add_nisp21pwd_entry,
+ mod_nisp21pwd_entry,
+ getnispdispnam,
+ getnispdisprid,
+ getnispdispent
+};
+
+struct passdb_ops *nisplus_initialize_password_db(void)
+{
+ return &nispasswd_ops;
+}
+
+#else
+ 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, ("add_nisppwd_entry: 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/pass_check.c b/source/passdb/pass_check.c
new file mode 100644
index 00000000000..d847407bbb4
--- /dev/null
+++ b/source/passdb/pass_check.c
@@ -0,0 +1,915 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* 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 HAVE_PAM
+/*******************************************************************
+check on PAM authentication
+********************************************************************/
+
+/* We first need some helper functions */
+#include <security/pam_appl.h>
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static char *PAM_username;
+static char *PAM_password;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int 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;
+
+ #define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) return PAM_CONV_ERR;
+
+ 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(PAM_username);
+ /* PAM frees resp */
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(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... */
+ free (reply);
+ return PAM_CONV_ERR;
+ }
+ }
+ if (reply) *resp = reply;
+ return PAM_SUCCESS;
+}
+static struct pam_conv PAM_conversation = {
+ &PAM_conv,
+ NULL
+};
+
+
+static BOOL pam_auth(char *user,char *password)
+{
+ pam_handle_t *pamh;
+ int pam_error;
+
+ /* Now use PAM to do authentication. For now, we won't worry about
+ * session logging, only authentication. Bail out if there are any
+ * errors. Since this is a limited protocol, and an even more limited
+ * function within a server speaking this protocol, we can't be as
+ * verbose as would otherwise make sense.
+ * Query: should we be using PAM_SILENT to shut PAM up?
+ */
+ #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
+ pam_end(pamh, 0); return False; \
+ }
+ PAM_password = password;
+ PAM_username = user;
+ pam_error = pam_start("samba", user, &PAM_conversation, &pamh);
+ PAM_BAIL;
+/* Setting PAM_SILENT stops generation of error messages to syslog
+ * to enable debugging on Red Hat Linux set:
+ * /etc/pam.d/samba:
+ * auth required /lib/security/pam_pwdb.so nullok shadow audit
+ * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
+ */
+ pam_error = pam_authenticate(pamh, PAM_SILENT);
+ PAM_BAIL;
+ /* It is not clear to me that account management is the right thing
+ * to do, but it is not clear that it isn't, either. This can be
+ * removed if no account management should be done. Alternately,
+ * put a pam_allow.so entry in /etc/pam.conf for account handling. */
+ pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
+ PAM_BAIL;
+ pam_end(pamh, PAM_SUCCESS);
+ /* If this point is reached, the user has been authenticated. */
+ return(True);
+}
+#endif
+
+
+#ifdef WITH_AFS
+/*******************************************************************
+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);
+ }
+ return(False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+/*****************************************************************
+ 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];
+
+ 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 become_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.
+ */
+
+ if (setregid(-1, pw->pw_gid) != 0) {
+ DEBUG(0,("Can't set egid to %d (%s)\n",
+ pw->pw_gid, strerror(errno)));
+ return False;
+ }
+
+ if (setreuid(-1, pw->pw_uid) != 0) {
+ setgid(0);
+ DEBUG(0,("Can't set euid to %d (%s)\n",
+ pw->pw_uid, strerror(errno)));
+ return False;
+ }
+
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
+
+ return(False);
+ }
+
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
+ user,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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
+
+ return(False);
+ }
+
+ 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ 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));
+
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ return(False);
+ }
+
+ DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
+ user, 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);
+ /* Go back to root, JRA. */
+ setuid(0);
+ setgid(0);
+ DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
+
+ return(False);
+ }
+
+ setuid(0);
+ setgid(0);
+
+ DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
+
+ 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 KRB5_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb5_auth(char *user,char *password)
+{
+ krb5_data tgtname = {
+ 0,
+ KRB5_TGS_NAME_SIZE,
+ KRB5_TGS_NAME
+ };
+ krb5_context kcontext;
+ krb5_principal kprinc;
+ krb5_principal server;
+ krb5_creds kcreds;
+ int options = 0;
+ krb5_address **addrs = (krb5_address **)0;
+ krb5_preauthtype *preauth = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_timestamp now;
+ krb5_ccache ccache = NULL;
+ int retval;
+ char *name;
+
+ if (retval=krb5_init_context(&kcontext)) {
+ return(False);
+ }
+
+ if (retval = krb5_timeofday(kcontext, &now)) {
+ return(False);
+ }
+
+ if (retval = krb5_cc_default(kcontext, &ccache)) {
+ return(False);
+ }
+
+ if (retval = krb5_parse_name(kcontext, user, &kprinc)) {
+ return(False);
+ }
+
+ ZERO_STRUCT(kcreds);
+
+ kcreds.client = kprinc;
+
+ if ((retval = krb5_build_principal_ext(kcontext, &server,
+ krb5_princ_realm(kcontext, kprinc)->length,
+ krb5_princ_realm(kcontext, kprinc)->data,
+ tgtname.length,
+ tgtname.data,
+ krb5_princ_realm(kcontext, kprinc)->length,
+ krb5_princ_realm(kcontext, kprinc)->data,
+ 0))) {
+ return(False);
+ }
+
+ kcreds.server = server;
+
+ retval = krb5_get_in_tkt_with_password(kcontext,
+ options,
+ addrs,
+ NULL,
+ preauth,
+ password,
+ 0,
+ &kcreds,
+ 0);
+
+ if (retval) {
+ return(False);
+ }
+
+ return(True);
+}
+#endif /* KRB5_AUTH */
+
+#ifdef KRB4_AUTH
+#include <krb.h>
+
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb4_auth(char *user,char *password)
+{
+ char realm[REALM_SZ];
+ char tkfile[MAXPATHLEN];
+
+ if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+ (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
+ }
+
+ (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
+ (int)getpid());
+
+ krb_set_tkt_string(tkfile);
+ if (krb_verify_user(user, "", realm,
+ password, 0,
+ "rmcd") == KSUCCESS) {
+ unlink(tkfile);
+ return 1;
+ }
+ unlink(tkfile);
+ return 0;
+}
+#endif /* KRB4_AUTH */
+
+#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);
+
+ 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 BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
+{
+ int len = strlen(s);
+ int i;
+
+#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 (string_combinations2(s,i+1,fn,N-1))
+ return(True);
+ s[i] = c;
+ }
+ return(False);
+}
+
+/****************************************************************************
+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)(char *),int N)
+{
+ int n;
+ for (n=1;n<=N;n++)
+ if (string_combinations2(s,0,fn,n)) return(True);
+ return(False);
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static BOOL password_check(char *password)
+{
+
+#ifdef HAVE_PAM
+ /* This falls through if the password check fails
+ - if HAVE_CRYPT is not defined this causes an error msg
+ saying Warning - no crypt available
+ - if HAVE_CRYPT is defined this is a potential security hole
+ as it may authenticate via the crypt call when PAM
+ settings say it should fail.
+ if (pam_auth(user,password)) return(True);
+ Hence we make a direct return to avoid a second chance!!!
+ */
+ return (pam_auth(this_user,password));
+#endif
+
+#ifdef WITH_AFS
+ if (afs_auth(this_user,password)) return(True);
+#endif
+
+#ifdef WITH_DFS
+ if (dfs_auth(this_user,password)) return(True);
+#endif
+
+#ifdef KRB5_AUTH
+ if (krb5_auth(this_user,password)) return(True);
+#endif
+
+#ifdef KRB4_AUTH
+ if (krb4_auth(this_user,password)) return(True);
+#endif
+
+#ifdef OSF1_ENH_SEC
+ {
+ BOOL 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);
+ }
+ return ret;
+ }
+#endif
+
+#ifdef ULTRIX_AUTH
+ return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
+#endif
+
+#ifdef LINUX_BIGCRYPT
+ return(linux_bigcrypt(password,this_salt,this_crypted));
+#endif
+
+#ifdef HAVE_BIGCRYPT
+ return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
+#endif
+
+#ifndef HAVE_CRYPT
+ DEBUG(1,("Warning - no crypt available\n"));
+ return(False);
+#else
+ return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
+#endif
+}
+
+
+
+/****************************************************************************
+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 True on correct match, False otherwise
+****************************************************************************/
+BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
+ BOOL (*fn)(char *, char *))
+{
+ pstring pass2;
+ int level = lp_passwordlevel();
+ struct passwd *pass;
+
+ if (password) password[pwlen] = 0;
+
+#if DEBUG_PASSWORD
+ 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);
+ }
+
+
+ DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
+
+ if (!pass) {
+ DEBUG(3,("Couldn't find user %s\n",user));
+ return(False);
+ }
+
+#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) {
+ 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)
+ 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,("No entry for user %s in protected database !\n",
+ user));
+ return(False);
+ }
+ }
+#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_user,pass->pw_name);
+ fstrcpy(this_salt,pass->pw_passwd);
+ /* crypt on some platforms (HPUX in particular)
+ won't work with more than 2 salt characters. */
+ this_salt[2] = 0;
+
+ fstrcpy(this_crypted,pass->pw_passwd);
+
+ if (!*this_crypted) {
+ if (!lp_null_passwords()) {
+ DEBUG(2,("Disallowing %s with null password\n",
+ this_user));
+ return(False);
+ }
+ if (!*password) {
+ DEBUG(3,("Allowing access to %s with null password\n",
+ this_user));
+ return(True);
+ }
+ }
+
+ /* try it as it came to us */
+ if (password_check(password)) {
+ if (fn) fn(user,password);
+ 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)) {
+ if (fn) fn(user,password);
+ return(True);
+ }
+
+ /* give up? */
+ if (level < 1) {
+
+ /* restore it */
+ fstrcpy(password,pass2);
+
+ return(False);
+ }
+
+ /* last chance - all combinations of up to level chars upper! */
+ strlower(password);
+
+ if (string_combinations(password,password_check,level)) {
+ if (fn) fn(user,password);
+ return(True);
+ }
+
+ /* restore it */
+ fstrcpy(password,pass2);
+
+ return(False);
+}
diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c
new file mode 100644
index 00000000000..15b2e8ed508
--- /dev/null
+++ b/source/passdb/passdb.c
@@ -0,0 +1,889 @@
+/*
+ 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+/*
+ * This is set on startup - it defines the SID for this
+ * machine.
+ */
+
+DOM_SID global_machine_sid;
+
+/*
+ * NOTE. All these functions are abstracted into a structure
+ * that points to the correct function for the selected database. JRA.
+ *
+ * NOTE. for the get/mod/add functions, there are two sets of functions.
+ * one supports struct sam_passwd, the other supports struct smb_passwd.
+ * for speed optimisation it is best to support both these sets.
+ *
+ * it is, however, optional to support one set but not the other: there
+ * is conversion-capability built in to passdb.c, and run-time error
+ * detection for when neither are supported.
+ *
+ * password database writers are recommended to implement the sam_passwd
+ * functions in a first pass, as struct sam_passwd contains more
+ * information, needed by the NT Domain support.
+ *
+ * a full example set of derivative functions are listed below. an API
+ * writer is expected to cut/paste these into their module, replace
+ * either one set (struct smb_passwd) or the other (struct sam_passwd)
+ * OR both, and optionally also to write display info routines
+ * (struct sam_disp_info). lkcl
+ *
+ */
+
+#if 0
+static struct smb_passwd *getPDBpwent (void *vp) { return pdb_sam_to_smb(getPDB21pwent(vp)); }
+static BOOL add_PDBpwd_entry (struct smb_passwd *newpwd) { return add_PDB21pwd_entry(pdb_smb_to_sam(newpwd)); }
+static BOOL mod_PDBpwd_entry (struct smb_passwd* pwd, BOOL override) { return mod_PDB21pwd_entry(pdb_smb_to_sam(pwd), override); }
+static struct smb_passwd *getPDBpwnam (char *name) { return pdb_sam_to_smb(getPDB21pwnam(name)); }
+static struct smb_passwd *getPDBpwuid (uid_t smb_userid) { return pdb_sam_to_smb(getPDB21pwuid(pdb_uid_to_user_rid(smb_userid))); }
+
+static struct sam_passwd *getPDB21pwent (void *vp) { return pdb_smb_to_sam(getPDBpwent(vp)); }
+static BOOL add_PDB21pwd_entry (struct sam_passwd *newpwd) { return add_PDBpwd_entry(pdb_sam_to_smb(newpwd)); }
+static BOOL mod_PDB21pwd_entry (struct sam_passwd* pwd, BOOL override) { return mod_PDBpwd_entry(pdb_sam_to_smb(pwd), override); }
+static struct sam_passwd *getPDB21pwnam (char *name) { return pdb_smb_to_sam(getPDBpwnam(name)); }
+static struct sam_passwd *getPDB21pwrid (uint32 rid) { return pdb_smb_to_sam(getPDBpwuid(pdb_user_rid_to_uid(rid))); }
+static struct sam_passwd *getPDB21pwuid (uid_t uid) { return pdb_smb_to_sam(getPDBpwuid(uid)); }
+
+static struct sam_disp_info *getPDBdispnam (char *name) { return pdb_sam_to_dispinfo(getPDB21pwnam(name)); }
+static struct sam_disp_info *getPDBdisprid (uint32 rid) { return pdb_sam_to_dispinfo(getPDB21pwrid(rid)); }
+static struct sam_disp_info *getPDBdispent (void *vp) { return pdb_sam_to_dispinfo(getPDB21pwent(vp)); }
+#endif /* 0 */
+
+static struct passdb_ops *pdb_ops;
+
+/***************************************************************
+ Initialize the password db operations.
+***************************************************************/
+
+BOOL initialize_password_db(void)
+{
+ if (pdb_ops)
+ {
+ return True;
+ }
+
+#ifdef WITH_NISPLUS
+ pdb_ops = nisplus_initialize_password_db();
+#elif defined(WITH_LDAP)
+ pdb_ops = ldap_initialize_password_db();
+#else
+ pdb_ops = file_initialize_password_db();
+#endif
+
+ return (pdb_ops != NULL);
+}
+
+/*
+ * Functions that return/manipulate a struct smb_passwd.
+ */
+
+/************************************************************************
+ Utility function to search smb passwd by uid. use this if your database
+ does not have search facilities.
+*************************************************************************/
+
+struct smb_passwd *iterate_getsmbpwuid(uid_t smb_userid)
+{
+ 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 = startsmbpwent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open smb password database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsmbpwent(fp)) != NULL && pwd->smb_userid != smb_userid)
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by smb_userid: %x\n", (int)smb_userid));
+ }
+
+ endsmbpwent(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_getsmbpwnam(char *name)
+{
+ struct smb_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by name: %s\n", name));
+
+ /* Open the sam password file - not for update. */
+ fp = startsmbpwent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open smb password database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsmbpwent(fp)) != NULL && !strequal(pwd->smb_name, name))
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by name: %s\n", name));
+ }
+
+ endsmbpwent(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 *startsmbpwent(BOOL update)
+{
+ return pdb_ops->startsmbpwent(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 endsmbpwent(void *vp)
+{
+ pdb_ops->endsmbpwent(vp);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smb passwd list.
+ *************************************************************************/
+
+struct smb_passwd *getsmbpwent(void *vp)
+{
+ return pdb_ops->getsmbpwent(vp);
+}
+
+/************************************************************************
+ Routine to add an entry to the smb passwd file.
+*************************************************************************/
+
+BOOL add_smbpwd_entry(struct smb_passwd *newpwd)
+{
+ return pdb_ops->add_smbpwd_entry(newpwd);
+}
+
+/************************************************************************
+ Routine to search the smb passwd file for an entry matching the username.
+ and then modify its password entry. We can't use the startsampwent()/
+ getsampwent()/endsampwent() 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
+************************************************************************/
+
+BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override)
+{
+ return pdb_ops->mod_smbpwd_entry(pwd, override);
+}
+
+/************************************************************************
+ Routine to search smb passwd by name.
+*************************************************************************/
+
+struct smb_passwd *getsmbpwnam(char *name)
+{
+ return pdb_ops->getsmbpwnam(name);
+}
+
+/************************************************************************
+ Routine to search smb passwd by uid.
+*************************************************************************/
+
+struct smb_passwd *getsmbpwuid(uid_t smb_userid)
+{
+ return pdb_ops->getsmbpwuid(smb_userid);
+}
+
+/*
+ * Functions that manupulate a struct sam_passwd.
+ */
+
+/************************************************************************
+ Utility function to search sam passwd by name. use this if your database
+ does not have search facilities.
+*************************************************************************/
+
+struct sam_passwd *iterate_getsam21pwnam(char *name)
+{
+ struct sam_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by name: %s\n", name));
+
+ /* Open the smb password database - not for update. */
+ fp = startsmbpwent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open sam password database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->smb_name, name))
+ {
+ DEBUG(10, ("iterate: %s 0x%x\n", pwd->smb_name, pwd->user_rid));
+ }
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by name: %s\n", name));
+ }
+
+ endsmbpwent(fp);
+ return pwd;
+}
+
+/************************************************************************
+ Utility function to search sam passwd by rid. use this if your database
+ does not have search facilities.
+
+ search capability by both rid and uid are needed as the rid <-> uid
+ mapping may be non-monotonic.
+
+*************************************************************************/
+
+struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
+{
+ struct sam_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by rid: %x\n", rid));
+
+ /* Open the smb password file - not for update. */
+ fp = startsmbpwent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open sam password database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
+ {
+ DEBUG(10, ("iterate: %s 0x%x\n", pwd->smb_name, pwd->user_rid));
+ }
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by user_rid: %x\n", rid));
+ }
+
+ endsmbpwent(fp);
+ return pwd;
+}
+
+/************************************************************************
+ Utility function to search sam passwd by uid. use this if your database
+ does not have search facilities.
+
+ search capability by both rid and uid are needed as the rid <-> uid
+ mapping may be non-monotonic.
+
+*************************************************************************/
+
+struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
+{
+ struct sam_passwd *pwd = NULL;
+ void *fp = NULL;
+
+ DEBUG(10, ("search by uid: %x\n", (int)uid));
+
+ /* Open the smb password file - not for update. */
+ fp = startsmbpwent(False);
+
+ if (fp == NULL)
+ {
+ DEBUG(0, ("unable to open sam password database.\n"));
+ return NULL;
+ }
+
+ while ((pwd = getsam21pwent(fp)) != NULL && pwd->smb_userid != uid)
+ ;
+
+ if (pwd != NULL)
+ {
+ DEBUG(10, ("found by smb_userid: %x\n", (int)uid));
+ }
+
+ endsmbpwent(fp);
+ return pwd;
+}
+
+/*************************************************************************
+ Routine to return a display info structure, by rid
+ *************************************************************************/
+struct sam_disp_info *getsamdisprid(uint32 rid)
+{
+ return pdb_ops->getsamdisprid(rid);
+}
+
+/*************************************************************************
+ Routine to return the next entry in the sam passwd list.
+ *************************************************************************/
+
+struct sam_passwd *getsam21pwent(void *vp)
+{
+ return pdb_ops->getsam21pwent(vp);
+}
+
+
+/************************************************************************
+ Routine to search sam passwd by name.
+*************************************************************************/
+
+struct sam_passwd *getsam21pwnam(char *name)
+{
+ return pdb_ops->getsam21pwnam(name);
+}
+
+/************************************************************************
+ Routine to search sam passwd by rid.
+*************************************************************************/
+
+struct sam_passwd *getsam21pwrid(uint32 rid)
+{
+ return pdb_ops->getsam21pwrid(rid);
+}
+
+
+/**********************************************************
+ **********************************************************
+
+ utility routines which are likely to be useful to all password
+ databases
+
+ **********************************************************
+ **********************************************************/
+
+/*************************************************************
+ initialises a struct sam_disp_info.
+ **************************************************************/
+
+static void pdb_init_dispinfo(struct sam_disp_info *user)
+{
+ if (user == NULL) return;
+ bzero(user, sizeof(*user));
+}
+
+/*************************************************************
+ initialises a struct smb_passwd.
+ **************************************************************/
+
+void pdb_init_smb(struct smb_passwd *user)
+{
+ if (user == NULL) return;
+ bzero(user, sizeof(*user));
+ user->pass_last_set_time = (time_t)-1;
+}
+
+/*************************************************************
+ initialises a struct sam_passwd.
+ **************************************************************/
+void pdb_init_sam(struct sam_passwd *user)
+{
+ if (user == NULL) return;
+ bzero(user, sizeof(*user));
+ user->logon_time = (time_t)-1;
+ user->logoff_time = (time_t)-1;
+ user->kickoff_time = (time_t)-1;
+ user->pass_last_set_time = (time_t)-1;
+ user->pass_can_change_time = (time_t)-1;
+ user->pass_must_change_time = (time_t)-1;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the sam passwd list.
+ *************************************************************************/
+
+struct sam_disp_info *pdb_sam_to_dispinfo(struct sam_passwd *user)
+{
+ static struct sam_disp_info disp_info;
+
+ if (user == NULL) return NULL;
+
+ pdb_init_dispinfo(&disp_info);
+
+ disp_info.smb_name = user->smb_name;
+ disp_info.full_name = user->full_name;
+ disp_info.user_rid = user->user_rid;
+
+ return &disp_info;
+}
+
+/*************************************************************
+ converts a sam_passwd structure to a smb_passwd structure.
+ **************************************************************/
+
+struct smb_passwd *pdb_sam_to_smb(struct sam_passwd *user)
+{
+ static struct smb_passwd pw_buf;
+
+ if (user == NULL) return NULL;
+
+ pdb_init_smb(&pw_buf);
+
+ pw_buf.smb_userid = user->smb_userid;
+ pw_buf.smb_name = user->smb_name;
+ pw_buf.smb_passwd = user->smb_passwd;
+ pw_buf.smb_nt_passwd = user->smb_nt_passwd;
+ pw_buf.acct_ctrl = user->acct_ctrl;
+ pw_buf.pass_last_set_time = user->pass_last_set_time;
+
+ return &pw_buf;
+}
+
+
+/**********************************************************
+ 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.
+
+ this function breaks coding standards minimum line width of 80 chars.
+ reason: vertical line-up code clarity - all case statements fit into
+ 15 lines, which is more important.
+ **********************************************************/
+
+uint16 pdb_decode_acct_ctrl(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 get the 32 hex characters and turn them
+ into a 16 byte array.
+**************************************************************/
+BOOL pdb_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);
+}
+
+/*******************************************************************
+ Group and User RID username mapping function
+ ********************************************************************/
+
+BOOL pdb_name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
+{
+ struct passwd *pw = Get_Pwnam(user_name, False);
+
+ 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;
+ }
+
+ if (user_in_list(user_name, lp_domain_guest_users()))
+ {
+ *u_rid = DOMAIN_USER_RID_GUEST;
+ }
+ else if (user_in_list(user_name, lp_domain_admin_users()))
+ {
+ *u_rid = DOMAIN_USER_RID_ADMIN;
+ }
+ else
+ {
+ /* 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 */
+ *g_rid = pdb_gid_to_group_rid(pw->pw_gid);
+
+ return True;
+}
+
+/****************************************************************************
+ 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_machine_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.
+****************************************************************************/
+BOOL pdb_generate_machine_sid(void)
+{
+ int fd;
+ char *p;
+ pstring sid_file;
+ fstring sid_string;
+ SMB_STRUCT_STAT st;
+ uchar raw_sid_data[12];
+
+ pstrcpy(sid_file, lp_smb_passwd_file());
+ p = strrchr(sid_file, '/');
+ if(p != NULL) {
+ *++p = '\0';
+ }
+
+ if (!directory_exist(sid_file, NULL)) {
+ if (dos_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 = 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;
+ }
+ close(fd);
+ return True;
+ }
+
+ /*
+ * The file contains no data - we may need to generate our
+ * own sid. Try the lp_domain_sid() first.
+ */
+
+ if(*lp_domain_sid())
+ fstrcpy( sid_string, lp_domain_sid());
+ else {
+ /*
+ * Generate the new sid data & turn it into a string.
+ */
+ int i;
+ generate_random_buffer( raw_sid_data, 12, True);
+
+ fstrcpy( sid_string, "S-1-5-21");
+ for( i = 0; i < 3; i++) {
+ fstring tmp_string;
+ slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4));
+ fstrcat( sid_string, tmp_string);
+ }
+ }
+
+ fstrcat(sid_string, "\n");
+
+ /*
+ * Ensure our new SID is valid.
+ */
+
+ if(!string_to_sid( &global_machine_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;
+ }
+
+ /*
+ * 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.
+ * Write out out SID data into the file.
+ */
+
+ if(fchmod(fd, 0644) < 0) {
+ DEBUG(0,("unable to set correct permissions on file %s. \
+Error was %s\n", sid_file, strerror(errno) ));
+ 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) ));
+ close(fd);
+ return False;
+ }
+
+ /*
+ * Unlock & exit.
+ */
+
+ do_file_lock( fd, 60, F_UNLCK);
+ close(fd);
+ return True;
+}
+
+/*******************************************************************
+ 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.
+ ********************************************************************/
+
+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;
+}
diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c
index 2dec15ffb43..0347df4ee9e 100644
--- a/source/passdb/smbpass.c
+++ b/source/passdb/smbpass.c
@@ -1,7 +1,6 @@
-#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.
+ * 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
@@ -19,286 +18,990 @@
*/
#include "includes.h"
-#include "loadparm.h"
-extern int DEBUGLEVEL;
+#ifdef USE_SMBPASS_DB
-int gotalarm;
+extern int pw_file_lock_depth;
+extern int DEBUGLEVEL;
+extern pstring samlogon_user;
+extern BOOL sam_logon_in_ssb;
-void
-gotalarm_sig()
+static char s_readbuf[1024];
+
+/***************************************************************
+ Start to enumerate the smbpasswd list. Returns a void pointer
+ to ensure no modification outside this module.
+****************************************************************/
+
+static void *startsmbfilepwent(BOOL update)
{
- gotalarm = 1;
+ FILE *fp = NULL;
+ char *pfile = lp_smb_passwd_file();
+
+ if (!*pfile) {
+ DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+ return (NULL);
+ }
+ DEBUG(10, ("startsmbfilepwent: opening file %s\n", pfile));
+
+ fp = fopen(pfile, update ? "r+b" : "rb");
+
+ if (fp == NULL) {
+ DEBUG(0, ("startsmbfilepwent: unable to open file %s\n", pfile));
+ return NULL;
+ }
+
+ /* Set a buffer to do more efficient reads */
+ setvbuf(fp, s_readbuf, _IOFBF, sizeof(s_readbuf));
+
+ if (!pw_file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, &pw_file_lock_depth))
+ {
+ DEBUG(0, ("startsmbfilepwent: 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;
}
-int
-do_pw_lock(int fd, int waitsecs, int type)
+/***************************************************************
+ End enumeration of the smbpasswd list.
+****************************************************************/
+
+static void endsmbfilepwent(void *vp)
{
- 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;
+ FILE *fp = (FILE *)vp;
+
+ pw_file_unlock(fileno(fp), &pw_file_lock_depth);
+ fclose(fp);
+ DEBUG(7, ("endsmbfilepwent: closed password file.\n"));
}
-int
-pw_file_lock(char *name, int type, int secs)
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ *************************************************************************/
+static struct smb_passwd *getsmbfilepwent(void *vp)
{
- 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;
+ /* 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.
+ */
+ 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, ("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(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 (!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, (char *)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,(char *)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 == '[')
+ {
+ 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(*p == ']')
+ p++;
+ 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;
+}
+
+/*************************************************************************
+ Routine to return the next entry in the smbpasswd list.
+ this function is a nice, messy combination of reading:
+ - the smbpasswd file
+ - the unix password database
+ - smb.conf options (not done at present).
+ *************************************************************************/
+
+static struct sam_passwd *getsmbfile21pwent(void *vp)
+{
+ struct smb_passwd *pw_buf = getsmbfilepwent(vp);
+ static struct sam_passwd user;
+ struct passwd *pwfile;
+
+ 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;
+
+ if (pw_buf == NULL) return NULL;
+
+ pwfile = getpwnam(pw_buf->smb_name);
+ if (pwfile == NULL) return NULL;
+
+ pdb_init_sam(&user);
+
+ pstrcpy(samlogon_user, pw_buf->smb_name);
+
+ if (samlogon_user[strlen(samlogon_user)-1] != '$')
+ {
+ /* XXXX hack to get standard_sub_basic() to use sam logon username */
+ /* possibly a better way would be to do a become_user() call */
+ sam_logon_in_ssb = True;
+
+ user.smb_userid = pw_buf->smb_userid;
+ user.smb_grpid = pwfile->pw_gid;
+
+ user.user_rid = pdb_uid_to_user_rid (user.smb_userid);
+ user.group_rid = pdb_gid_to_group_rid(user.smb_grpid );
+
+ pstrcpy(full_name , pwfile->pw_gecos );
+ pstrcpy(logon_script , lp_logon_script ());
+ pstrcpy(profile_path , lp_logon_path ());
+ pstrcpy(home_drive , lp_logon_drive ());
+ pstrcpy(home_dir , lp_logon_home ());
+ pstrcpy(acct_desc , "");
+ pstrcpy(workstations , "");
+
+ sam_logon_in_ssb = False;
+ }
+ else
+ {
+ user.smb_userid = pw_buf->smb_userid;
+ user.smb_grpid = pwfile->pw_gid;
+
+ user.user_rid = pdb_uid_to_user_rid (user.smb_userid);
+ user.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 , "");
}
- return fd;
+
+ user.smb_name = pw_buf->smb_name;
+ user.full_name = full_name;
+ user.home_dir = home_dir;
+ user.dir_drive = home_drive;
+ user.logon_script = logon_script;
+ user.profile_path = profile_path;
+ user.acct_desc = acct_desc;
+ user.workstations = workstations;
+
+ user.unknown_str = NULL; /* don't know, yet! */
+ user.munged_dial = NULL; /* "munged" dial-back telephone number */
+
+ user.smb_nt_passwd = pw_buf->smb_nt_passwd;
+ user.smb_passwd = pw_buf->smb_passwd;
+
+ 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 = 0x00020000; /* don't know */
+ user.unknown_5 = 0x000004ec; /* don't know */
+
+ return &user;
}
-int
-pw_file_unlock(int fd)
+/*************************************************************************
+ 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 getsmbfilepwpos(void *vp)
{
- do_pw_lock(fd, 5, F_UNLCK);
- return close(fd);
+ return (SMB_BIG_UINT)sys_ftell((FILE *)vp);
}
-/*
- * Routine to get the next 32 hex characters and turn them
- * into a 16 byte array.
- */
+/*************************************************************************
+ Set the current position in the smbpasswd list from an SMB_BIG_UINT.
+ This must be treated as an opaque token.
+*************************************************************************/
-static int gethexpwd(char *p, char *pwd)
+static BOOL setsmbfilepwpos(void *vp, SMB_BIG_UINT tok)
{
- 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);
+ return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET);
}
-/*
- * Routine to search the smbpasswd file for an entry matching the username.
- */
-struct smb_passwd *
-get_smbpwnam(char *name)
+/************************************************************************
+ Routine to add an entry to the smbpasswd file.
+*************************************************************************/
+
+static BOOL add_smbfilepwd_entry(struct smb_passwd *newpwd)
{
- /* 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));
+ char *pfile = lp_smb_passwd_file();
+ struct smb_passwd *pwd = NULL;
+ FILE *fp = NULL;
- fp = fopen(pfile, "r");
+ int i;
+ int wr_len;
- 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));
+ int fd;
+ int new_entry_length;
+ char *new_entry;
+ SMB_OFF_T offpos;
+ char *p;
- 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';
+ /* Open the smbpassword file - for update. */
+ fp = startsmbfilepwent(True);
+
+ 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);
+ 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);
+ return False;
+ }
+
+ 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, ("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);
+ return False;
+ }
+
+ 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)time(NULL));
#ifdef DEBUG_PASSWORD
- DEBUG(100, ("get_smbpwnam: got line |%s|\n", linebuf));
+ DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d entry_len %d made line |%s|",
+ fd, new_entry_length, strlen(new_entry), new_entry));
#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;
+ if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry)) {
+ 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);
+ free(new_entry);
+ return False;
+ }
+
+ free(new_entry);
+ endsmbfilepwent(fp);
+ return True;
}
-#else
-void
-smbpass_dummy(void)
+
+/************************************************************************
+ 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(struct smb_passwd* pwd, BOOL override)
{
-} /* To avoid compiler complaints */
+ /* 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 = 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(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 both NT and lanman passwords are provided - reset password
+ * not required flag.
+ */
+
+ if(pwd->smb_passwd != NULL || pwd->smb_nt_passwd != NULL) {
+ /* Reqiure password in the future (should ACB_DISABLED also be reset?) */
+ pwd->acct_ctrl &= ~(ACB_PWNOTREQ);
+ }
+
+ 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 {
+ /*
+ * 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;
+ }
+ }
+
+ /* 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] = ':';
+
+ /* Add on the account info bits and the time of last
+ password change. */
+
+ pwd->pass_last_set_time = time(NULL);
+
+ 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;
+}
+
+/*
+ * Stub functions - implemented in terms of others.
+ */
+
+static BOOL mod_smbfile21pwd_entry(struct sam_passwd* pwd, BOOL override)
+{
+ return mod_smbfilepwd_entry(pdb_sam_to_smb(pwd), override);
+}
+
+static BOOL add_smbfile21pwd_entry(struct sam_passwd *newpwd)
+{
+ return add_smbfilepwd_entry(pdb_sam_to_smb(newpwd));
+}
+
+static struct sam_disp_info *getsmbfiledispnam(char *name)
+{
+ return pdb_sam_to_dispinfo(getsam21pwnam(name));
+}
+
+static struct sam_disp_info *getsmbfiledisprid(uint32 rid)
+{
+ return pdb_sam_to_dispinfo(getsam21pwrid(rid));
+}
+
+static struct sam_disp_info *getsmbfiledispent(void *vp)
+{
+ return pdb_sam_to_dispinfo(getsam21pwent(vp));
+}
+
+static struct passdb_ops file_ops = {
+ startsmbfilepwent,
+ endsmbfilepwent,
+ getsmbfilepwpos,
+ setsmbfilepwpos,
+ iterate_getsmbpwnam, /* In passdb.c */
+ iterate_getsmbpwuid, /* In passdb.c */
+ getsmbfilepwent,
+ add_smbfilepwd_entry,
+ mod_smbfilepwd_entry,
+ getsmbfile21pwent,
+ iterate_getsam21pwnam,
+ iterate_getsam21pwuid,
+ iterate_getsam21pwrid,
+ add_smbfile21pwd_entry,
+ mod_smbfile21pwd_entry,
+ getsmbfiledispnam,
+ getsmbfiledisprid,
+ getsmbfiledispent
+};
+
+struct passdb_ops *file_initialize_password_db(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/passdb/smbpassfile.c b/source/passdb/smbpassfile.c
new file mode 100644
index 00000000000..8542ad081d2
--- /dev/null
+++ b/source/passdb/smbpassfile.c
@@ -0,0 +1,320 @@
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+static int gotalarm;
+int pw_file_lock_depth = 0;
+
+/***************************************************************
+ 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(5);
+ 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 pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+ if (fd < 0)
+ return False;
+
+ (*plock_depth)++;
+
+ if(pw_file_lock_depth == 0) {
+ if (!do_file_lock(fd, secs, type)) {
+ DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+BOOL pw_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,("pw_file_unlock: unlocking file failed, error = %s.\n",
+ strerror(errno)));
+ return ret;
+}
+
+static int mach_passwd_lock_depth;
+static FILE *mach_passwd_fp;
+
+/************************************************************************
+ Routine to get the name for a trust account file.
+************************************************************************/
+
+static void get_trust_account_file_name( char *domain, char *name, char *mac_file)
+{
+ unsigned int mac_file_len;
+ char *p;
+
+ pstrcpy(mac_file, lp_smb_passwd_file());
+ p = strrchr(mac_file, '/');
+ if(p != NULL)
+ *++p = '\0';
+
+ mac_file_len = strlen(mac_file);
+
+ if ((int)(sizeof(pstring) - mac_file_len - strlen(domain) - strlen(name) - 6) < 0)
+ {
+ DEBUG(0,("trust_password_lock: path %s too long to add trust details.\n",
+ mac_file));
+ return;
+ }
+
+ pstrcat(mac_file, domain);
+ pstrcat(mac_file, ".");
+ pstrcat(mac_file, name);
+ pstrcat(mac_file, ".mac");
+}
+
+/************************************************************************
+ Routine to lock the trust account password file for a domain.
+************************************************************************/
+
+BOOL trust_password_lock( char *domain, char *name, BOOL update)
+{
+ pstring mac_file;
+
+ if(mach_passwd_lock_depth == 0) {
+
+ get_trust_account_file_name( domain, name, mac_file);
+
+ if((mach_passwd_fp = fopen(mac_file, "r+b")) == NULL) {
+ if(errno == ENOENT && update) {
+ mach_passwd_fp = fopen(mac_file, "w+b");
+ }
+
+ if(mach_passwd_fp == NULL) {
+ DEBUG(0,("trust_password_lock: cannot open file %s - Error was %s.\n",
+ mac_file, strerror(errno) ));
+ return False;
+ }
+ }
+
+ chmod(mac_file, 0600);
+
+ if(!pw_file_lock(fileno(mach_passwd_fp), (update ? F_WRLCK : F_RDLCK),
+ 60, &mach_passwd_lock_depth))
+ {
+ DEBUG(0,("trust_password_lock: cannot lock file %s\n", mac_file));
+ fclose(mach_passwd_fp);
+ return False;
+ }
+
+ }
+
+ return True;
+}
+
+/************************************************************************
+ Routine to unlock the trust account password file for a domain.
+************************************************************************/
+
+BOOL trust_password_unlock(void)
+{
+ BOOL ret = pw_file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth);
+ if(mach_passwd_lock_depth == 0)
+ fclose(mach_passwd_fp);
+ return ret;
+}
+
+/************************************************************************
+ Routine to delete the trust account password file for a domain.
+************************************************************************/
+
+BOOL trust_password_delete( char *domain, char *name )
+{
+ pstring mac_file;
+
+ get_trust_account_file_name( domain, name, mac_file);
+ return (unlink( mac_file ) == 0);
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain.
+ The user of this function must have locked the trust password file.
+************************************************************************/
+
+BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time)
+{
+ char linebuf[256];
+ char *p;
+ int i;
+
+ linebuf[0] = '\0';
+
+ *pass_last_set_time = (time_t)0;
+ memset(ret_pwd, '\0', 16);
+
+ if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) {
+ DEBUG(0,("get_trust_account_password: Failed to seek to start of file. Error was %s.\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ fgets(linebuf, sizeof(linebuf), mach_passwd_fp);
+ if(ferror(mach_passwd_fp)) {
+ DEBUG(0,("get_trust_account_password: Failed to read password. Error was %s.\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ if(linebuf[strlen(linebuf)-1] == '\n')
+ linebuf[strlen(linebuf)-1] = '\0';
+
+ /*
+ * The length of the line read
+ * must be 45 bytes ( <---XXXX 32 bytes-->:TLC-12345678
+ */
+
+ if(strlen(linebuf) != 45) {
+ DEBUG(0,("get_trust_account_password: Malformed trust password file (wrong length \
+- was %d, should be 45).\n", strlen(linebuf)));
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
+#endif
+ return False;
+ }
+
+ /*
+ * Get the hex password.
+ */
+
+ if (!pdb_gethexpwd((char *)linebuf, (char *)ret_pwd) || linebuf[32] != ':' ||
+ strncmp(&linebuf[33], "TLC-", 4)) {
+ DEBUG(0,("get_trust_account_password: Malformed trust password file (incorrect format).\n"));
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
+#endif
+ return False;
+ }
+
+ /*
+ * Get the last changed time.
+ */
+ p = &linebuf[37];
+
+ for(i = 0; i < 8; i++) {
+ if(p[i] == '\0' || !isxdigit((int)p[i])) {
+ DEBUG(0,("get_trust_account_password: Malformed trust password file (no timestamp).\n"));
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
+#endif
+ return False;
+ }
+ }
+
+ /*
+ * p points at 8 characters of hex digits -
+ * read into a time_t as the seconds since
+ * 1970 that the password was last changed.
+ */
+
+ *pass_last_set_time = (time_t)strtol(p, NULL, 16);
+
+ return True;
+}
+
+/************************************************************************
+ Routine to get the trust account password for a domain.
+ The user of this function must have locked the trust password file.
+************************************************************************/
+
+BOOL set_trust_account_password( unsigned char *md4_new_pwd)
+{
+ char linebuf[64];
+ int i;
+
+ if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) {
+ DEBUG(0,("set_trust_account_password: Failed to seek to start of file. Error was %s.\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ for (i = 0; i < 16; i++)
+ slprintf(&linebuf[(i*2)], sizeof(linebuf) - (i*2) - 1, "%02X", md4_new_pwd[i]);
+
+ slprintf(&linebuf[32], 32, ":TLC-%08X\n", (unsigned)time(NULL));
+
+ if(fwrite( linebuf, 1, 46, mach_passwd_fp)!= 46) {
+ DEBUG(0,("set_trust_account_password: Failed to write file. Warning - the trust \
+account is now invalid. Please recreate. Error was %s.\n", strerror(errno) ));
+ return False;
+ }
+
+ fflush(mach_passwd_fp);
+ return True;
+}
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/pcap.c b/source/printing/pcap.c
index 8973b1627fb..d51e69ad743 100644
--- a/source/printing/pcap.c
+++ b/source/printing/pcap.c
@@ -2,11 +2,13 @@
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
This 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,13 +51,14 @@
* 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.
*/
#include "includes.h"
#include "smb.h"
-#include "loadparm.h"
-#include "pcap.h"
extern int DEBUGLEVEL;
@@ -120,7 +123,7 @@ static void ScanQconfig_fn(char *psz,void (*fn)())
p = strtok(line,":");
if (strcmp(p,"bsh")!=0)
{
- strcpy(name,p);
+ pstrcpy(name,p);
iEtat = 1;
continue;
}
@@ -179,7 +182,7 @@ static BOOL ScanQconfig(char *psz,char *pszPrintername)
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;
@@ -229,8 +232,9 @@ static BOOL ScanQconfig(char *psz,char *pszPrintername)
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
@@ -257,10 +261,17 @@ BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
DEBUG(0,( "No printcap file name configured!\n"));
return(False);
}
+
+#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)
{
DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
@@ -285,7 +296,7 @@ BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
if (strequal(p,pszPrintername))
{
/* normalise the case */
- strcpy(pszPrintername,p);
+ pstrcpy(pszPrintername,p);
free(line);
fclose(pfile);
return(True);
@@ -294,7 +305,6 @@ BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
}
}
-
fclose(pfile);
return(False);
}
@@ -304,7 +314,7 @@ BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname)
run a function on each printer name in the printcap file. The function is
passed the primary name and the comment (if possible)
***************************************************************************/
-void pcap_printer_fn(void (*fn)())
+void pcap_printer_fn(void (*fn)(char *, char *))
{
pstring name,comment;
char *line;
@@ -319,13 +329,21 @@ void pcap_printer_fn(void (*fn)())
return;
}
+#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)
{
DEBUG(0,( "Unable to open printcap file %s for read!\n", psz));
@@ -358,10 +376,10 @@ 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;
}
@@ -374,7 +392,7 @@ void pcap_printer_fn(void (*fn)())
}
comment[60] = 0;
- name[8] = 0;
+ name[MAXPRINTERLEN] = 0;
if (*name)
fn(name,comment);
diff --git a/source/printing/print_svid.c b/source/printing/print_svid.c
new file mode 100644
index 00000000000..1f9f75a4fa7
--- /dev/null
+++ b/source/printing/print_svid.c
@@ -0,0 +1,121 @@
+/*
+ * 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
+
+extern int DEBUGLEVEL;
+
+typedef struct printer {
+ char *name;
+ struct printer *next;
+} printer_t;
+static printer_t *printers = NULL;
+
+static void populate_printers(void)
+{
+ FILE *fp;
+
+ if ((fp = popen("/usr/bin/lpstat -v", "r")) != NULL) {
+ char buf[BUFSIZ];
+
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ printer_t *ptmp;
+ char *name, *tmp;
+
+ /* eat "system/device for " */
+ if (((tmp = strchr(buf, ' ')) == NULL) ||
+ ((tmp = strchr(++tmp, ' ')) == NULL))
+ continue;
+ name = ++tmp;
+
+ /* truncate the ": ..." */
+ if ((tmp = strchr(name, ':')) != NULL)
+ *tmp = '\0';
+
+ /* add it to the cache */
+ if ((ptmp = malloc(sizeof (*ptmp))) != NULL) {
+ ZERO_STRUCTP(ptmp);
+ ptmp->name = strdup(name);
+ ptmp->next = printers;
+ printers = ptmp;
+ }
+ }
+ pclose(fp);
+ } else {
+ DEBUG(0,( "Unable to run lpstat!\n"));
+ }
+}
+
+
+/*
+ * 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) {}
+#endif
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 1dd8921800a..4df965204a0 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
printing 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,10 +20,7 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
static BOOL * lpq_cache_reset=NULL;
@@ -52,92 +49,84 @@ 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)
+static char *build_print_command(connection_struct *conn,
+ char *command,
+ char *syscmd, char *filename1)
{
- int snum = SNUM(cnum);
- char *tstr;
- pstring filename;
+ int snum = SNUM(conn);
+ 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);
- }
+ /* 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);
+ /* 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)));
- }
+ /* 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;
+ if (strstr(syscmd,"%s")) {
+ pstrcpy(filename,filename1);
- /* 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, "%s", filename);
+ }
- string_sub(syscmd, "%f", filename1);
+ 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);
- }
+ /* 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);
+ string_sub(syscmd, "%p", tstr);
- standard_sub(cnum,syscmd);
+ standard_sub(conn,syscmd);
- return (syscmd);
+ return (syscmd);
}
/****************************************************************************
print a file - called on closing the file
****************************************************************************/
-void print_file(int fnum)
+void print_file(connection_struct *conn, files_struct *file)
{
- pstring syscmd;
- int cnum = Files[fnum].cnum;
- int snum=SNUM(cnum);
- char *tempstr;
+ pstring syscmd;
+ int snum = SNUM(conn);
+ char *tempstr;
- *syscmd = 0;
+ *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;
- }
+ if (file_size(file->fsp_name) <= 0) {
+ DEBUG(3,("Discarding null print job %s\n",file->fsp_name));
+ dos_unlink(file->fsp_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"));
+ tempstr = build_print_command(conn,
+ PRINTCOMMAND(snum),
+ syscmd, file->fsp_name);
+ if (tempstr != NULL) {
+ int ret = smbrun(syscmd,NULL,False);
+ DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+ } else {
+ DEBUG(0,("Null print command?\n"));
+ }
- lpq_reset(snum);
+ lpq_reset(snum);
}
static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -147,9 +136,9 @@ static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
/*******************************************************************
process time fields
********************************************************************/
-static time_t EntryTime(string tok[], int ptr, int count, int minimum)
+static time_t EntryTime(fstring tok[], int ptr, int count, int minimum)
{
- time_t jobtime;
+ time_t jobtime,jobtime1;
jobtime = time(NULL); /* default case: take current time */
if (count >= minimum) {
@@ -181,7 +170,9 @@ static time_t EntryTime(string tok[], int ptr, int count, int minimum)
t->tm_hour = hour;
t->tm_min = min;
t->tm_sec = sec;
- jobtime = mktime(t);
+ jobtime1 = mktime(t);
+ if (jobtime1 != (time_t)-1)
+ jobtime = jobtime1;
}
}
return jobtime;
@@ -222,7 +213,7 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
#define NTOK 5
#endif /* OSF1 */
- string tok[NTOK];
+ fstring tok[NTOK];
int count=0;
#ifdef OSF1
@@ -237,27 +228,30 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
string_sub(line,"(","\"");
string_sub(line,")","\"");
- for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
+ for (count=0;
+ count<NTOK &&
+ next_token(&line,tok[count],NULL, sizeof(tok[count]));
+ 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 (!isdigit((int)*tok[JOBTOK]) || !isdigit((int)*tok[TOTALTOK])) return(False);
/* if the fname contains a space then use STDIN */
if (strchr(tok[FILETOK],' '))
- strcpy(tok[FILETOK],"STDIN");
+ fstrcpy(tok[FILETOK],"STDIN");
/* only take the last part of the filename */
{
- string tmp;
+ fstring tmp;
char *p = strrchr(tok[FILETOK],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[FILETOK],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[FILETOK],tmp);
}
}
@@ -276,6 +270,189 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
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"
+*/
+static time_t LPRng_time(fstring tok[],int pos)
+{
+ time_t jobtime;
+ struct tm *t;
+ fstring tmp_time;
+
+ jobtime = time(NULL); /* default case: take current time */
+ t = localtime(&jobtime);
+ t->tm_hour = atoi(tok[pos]);
+ fstrcpy(tmp_time,tok[pos]);
+ t->tm_min = atoi(tmp_time+3);
+ t->tm_sec = atoi(tmp_time+6);
+ jobtime = mktime(t);
+
+ return jobtime;
+}
+
+
+/****************************************************************************
+ parse a lpq line
+ <magnus@hum.auc.dk>
+ Most of the code is directly reused from parse_lpq_bsd()
+
+here are two examples of lpq output under lprng (LPRng-2.3.0)
+
+Printer: humprn@hum-fak
+ Queue: 1 printable job
+ Server: pid 4840 active, Unspooler: pid 4841 active
+ Status: job 'cfA659hum-fak', closing device at Fri Jun 21 10:10:21 1996
+ Rank Owner Class Job Files Size Time
+active magnus@hum-fak A 659 /var/spool/smb/Notesblok-ikke-na4024 10:03:31
+
+Printer: humprn@hum-fak (printing disabled)
+ Queue: 1 printable job
+ Warning: no server present
+ Status: finished operations at Fri Jun 21 10:10:32 1996
+ Rank Owner Class Job Files Size Time
+1 magnus@hum-fak A 387 /var/spool/smb/netbudget.xls 21230 10:50:53
+
+******************************************************************************
+
+NEW FOR LPRng-3.3.5 !
+
+<reinelt@eunet.at>
+This will not happen anymore: with LPRng-3.3.5 there is always a blank between
+the filename and the size, and the format has changed:
+
+Printer: lj6@lizard 'HP LaserJet 6P'
+ Queue: 2 printable jobs
+ Server: pid 11941 active
+ Unspooler: pid 11942 active
+ Status: printed all 1818 bytes at 19:49:59
+ Rank Owner/ID Class Job Files Size Time
+active root@lizard+937 A 937 (stdin) 1818 19:49:58
+2 root@lizard+969 A 969 junk.txt 2170 19:50:12
+
+****************************************************************************/
+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 5
+#define LPRNG_TIMETOK 6
+#define LPRNG_NTOK 7
+
+/****************************************************************************
+From lpd_status.c in LPRng source.
+0 1 2 3 4 5 6 7
+12345678901234567890123456789012345678901234567890123456789012345678901234
+" Rank Owner Class Job Files Size Time"
+ plp_snprintf( msg, sizeof(msg), "%-6s %-19s %c %03d %-32s",
+ number, line, priority, cfp->number, error );
+ plp_snprintf( msg + len, sizeof(msg)-len, "%4d",
+ cfp->jobsize );
+ plp_snprintf( msg+len, sizeof(msg)-len, " %s",
+ Time_str( 1, cfp->statb.st_ctime ) );
+****************************************************************************/
+ /* The following define's are to be able to adjust the values if the
+LPRng source changes. This is from version 2.3.0. Magnus */
+#define SPACE_W 1
+#define RANK_W 6
+#define OWNER_W 19
+#define CLASS_W 1
+#define JOB_W 3
+#define FILE_W 32
+/* The JOBSIZE_W is too small for big jobs, so time is pushed to the right */
+#define JOBSIZE_W 4
+
+#define RANK_POS 0
+#define OWNER_POS RANK_POS+RANK_W+SPACE_W
+#define CLASS_POS OWNER_POS+OWNER_W+SPACE_W
+#define JOB_POS CLASS_POS+CLASS_W+SPACE_W
+#define FILE_POS JOB_POS+JOB_W+SPACE_W
+#define JOBSIZE_POS FILE_POS+FILE_W
+
+
+ fstring tok[LPRNG_NTOK];
+ int count=0;
+
+#ifdef OLD_LPRNG
+/* We only need this bugfix for older versions of lprng - current
+ information is that version 3.3.5 must not have this line
+ in order to work correctly.
+*/
+
+/*
+Need to insert one space in front of the size, to be able to use
+next_token() unchanged. I would have liked to be able to insert a
+space instead, to prevent losing that one char, but perl has spoiled
+me :-\ So I did it the easiest way.
+
+HINT: Use as short a path as possible for the samba spool directory.
+A long spool-path will just waste significant chars of the file name.
+*/
+
+ line[JOBSIZE_POS-1]=' ';
+#endif /* OLD_LPRNG */
+
+ /* handle the case of "(stdin)" as a filename */
+ string_sub(line,"stdin","STDIN");
+ string_sub(line,"(","\"");
+ string_sub(line,")","\"");
+
+ for (count=0;
+ count<LPRNG_NTOK &&
+ next_token(&line,tok[count],NULL, sizeof(tok[count]));
+ count++) ;
+
+ /* we must get LPRNG_NTOK tokens */
+ if (count < LPRNG_NTOK)
+ return(False);
+
+ /* the Job and Total columns must be integer */
+ if (!isdigit((int)*tok[LPRNG_JOBTOK]) || !isdigit((int)*tok[LPRNG_TOTALTOK])) return(False);
+
+ /* if the fname contains a space then use STDIN */
+ /* I do not understand how this would be possible. Magnus. */
+ if (strchr(tok[LPRNG_FILETOK],' '))
+ fstrcpy(tok[LPRNG_FILETOK],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr(tok[LPRNG_FILETOK],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[LPRNG_FILETOK],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[LPRNG_JOBTOK]);
+ buf->size = atoi(tok[LPRNG_TOTALTOK]);
+ if (strequal(tok[LPRNG_RANKTOK],"active"))
+ buf->status = LPQ_PRINTING;
+ else if (strequal(tok[LPRNG_RANKTOK],"hold"))
+ buf->status = LPQ_PAUSED;
+ else
+ buf->status = LPQ_QUEUED;
+ /* buf->time = time(NULL); */
+ buf->time = LPRng_time(tok,LPRNG_TIMETOK);
+DEBUG(3,("Time reported for job %d is %s", buf->job, ctime(&buf->time)));
+ StrnCpy(buf->user,tok[LPRNG_USERTOK],sizeof(buf->user)-1);
+ StrnCpy(buf->file,tok[LPRNG_FILETOK],sizeof(buf->file)-1);
+#ifdef LPRNG_PRIOTOK
+ /* Here I try to map the CLASS char to a number, but the number
+ is never shown in Print Manager under NT anyway... Magnus. */
+ buf->priority = atoi(tok[LPRNG_PRIOTOK]-('A'-1));
+#else
+ buf->priority = 1;
+#endif
+ return(True);
+}
+
/*******************************************************************
@@ -292,7 +469,7 @@ lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
********************************************************************/
static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
{
- string tok[11];
+ fstring tok[11];
int count=0;
/* handle the case of "(standard input)" as a filename */
@@ -300,34 +477,37 @@ static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
string_sub(line,"(","\"");
string_sub(line,")","\"");
- for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
+ 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))
+ if ((count == 7) && ((strcmp(tok[0],"QUEUED") == 0) || (strcmp(tok[0],"HELD") == 0)))
{
/* the 2nd and 5th columns must be integer */
- if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
+ 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(tok[2],' '))
- strcpy(tok[2],"STDIN");
+ fstrcpy(tok[2],"STDIN");
/* only take the last part of the filename */
{
- string tmp;
+ fstring tmp;
char *p = strrchr(tok[2],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[2],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[2],tmp);
}
}
buf->job = atoi(tok[1]);
- buf->status = LPQ_QUEUED;
+ 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);
@@ -342,20 +522,20 @@ static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
else
{
/* the 4th and 9th columns must be integer */
- if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
+ 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(tok[4],' '))
- strcpy(tok[4],"STDIN");
+ fstrcpy(tok[4],"STDIN");
/* only take the last part of the filename */
{
- string tmp;
+ fstring tmp;
char *p = strrchr(tok[4],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[4],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[4],tmp);
}
}
@@ -387,7 +567,7 @@ 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 fstring jobuser;
static int jobid;
static int jobprio;
static time_t jobtime;
@@ -397,12 +577,12 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
static int base_prio;
int count;
- char TAB = '\011';
- string tok[12];
+ char htab = '\011';
+ fstring tok[12];
/* If a line begins with a horizontal TAB, it is a subline type */
- if (line[0] == TAB) { /* subline */
+ if (line[0] == htab) { /* subline */
/* check if it contains the base priority */
if (!strncmp(line,"\tfence priority : ",18)) {
base_prio=atoi(&line[18]);
@@ -414,16 +594,16 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
string_sub(line,"(","\"");
string_sub(line,")","\"");
- for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
+ 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(*tok[1])) return(False);
+ if (!isdigit((int)*tok[1])) return(False);
/* if the fname contains a space then use STDIN */
if (strchr(tok[0],' '))
- strcpy(tok[0],"STDIN");
+ fstrcpy(tok[0],"STDIN");
buf->size = atoi(tok[1]);
StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
@@ -450,14 +630,14 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
/* handle the dash in the job id */
string_sub(line,"-"," ");
- for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
+ 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(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
+ 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]);
@@ -493,29 +673,29 @@ 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];
+ fstring 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++) ;
+ 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(*tok[1]) || !isdigit(*tok[3])) return(False);
- if (!isdigit(*tok[5])) return(False);
+ 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(tok[2],'!')))
{
- string tmp;
- strcpy(tmp,p+1);
- strcpy(tok[2],tmp);
+ fstring tmp;
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[2],tmp);
}
@@ -546,7 +726,7 @@ Printer: txt (ready)
****************************************************************************/
static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
{
- string tok[7];
+ fstring tok[7];
int count=0;
DEBUG(0,("antes [%s]\n", line));
@@ -564,23 +744,23 @@ static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
- for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
+ 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(*tok[2]) || !isdigit(*tok[4])) return(False);
+ if (!isdigit((int)*tok[2]) || !isdigit((int)*tok[4])) return(False);
/* only take the last part of the filename */
{
- string tmp;
+ fstring tmp;
char *p = strrchr(tok[6],'/');
if (p)
{
- strcpy(tmp,p+1);
- strcpy(tok[6],tmp);
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
}
}
@@ -596,6 +776,154 @@ static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
}
+/****************************************************************************
+ 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 */
+ string_sub(line,"stdin","STDIN");
+ string_sub(line,"(","\"");
+ string_sub(line,")","\"");
+
+ 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(tok[6],' '))
+ fstrcpy(tok[6],"STDIN");
+
+ /* only take the last part of the filename */
+ {
+ fstring tmp;
+ char *p = strrchr(tok[6],'/');
+ if (p)
+ {
+ fstrcpy(tmp,p+1);
+ fstrcpy(tok[6],tmp);
+ }
+ }
+
+
+ buf->job = atoi(tok[4]);
+
+ buf->size = atoi(tok[7]);
+ if (strchr(tok[7],'K'))
+ buf->size *= 1024;
+ if (strchr(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*/
+ string_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]) + 1900; break;
+ default: t->tm_year = atoi(tok[count+2]) + 2000; 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);
+}
+
char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
@@ -610,7 +938,7 @@ static BOOL parse_lpq_entry(int snum,char *line,
{
BOOL ret;
- switch (lp_printing())
+ switch (lp_printing(snum))
{
case PRINT_SYSV:
ret = parse_lpq_sysv(line,buf,first);
@@ -624,6 +952,15 @@ static BOOL parse_lpq_entry(int snum,char *line,
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;
default:
ret = parse_lpq_bsd(line,buf,first);
break;
@@ -635,10 +972,16 @@ static BOOL parse_lpq_entry(int snum,char *line,
/* 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);
+ pstrcpy(buf->user,sesssetup_user);
}
#endif
+ /* We don't want the newline in the status message. */
+ {
+ char *p = strchr(line,'\n');
+ if (p) *p = 0;
+ }
+
if (status && !ret)
{
/* a few simple checks to see if the line might be a
@@ -653,18 +996,21 @@ static BOOL parse_lpq_entry(int snum,char *line,
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;
}
@@ -676,116 +1022,102 @@ static BOOL parse_lpq_entry(int snum,char *line,
/****************************************************************************
get a printer queue
****************************************************************************/
-int get_printqueue(int snum,int cnum,print_queue_struct **queue,
+int get_printqueue(int snum,
+ connection_struct *conn,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);
- }
+ char *lpq_command = lp_lpqcommand(snum);
+ char *printername = PRINTERNAME(snum);
+ int ret=0,count=0;
+ pstring syscmd;
+ fstring outfile;
+ pstring line;
+ FILE *f;
+ SMB_STRUCT_STAT sbuf;
+ BOOL dorun=True;
+ int cachetime = lp_lpqcachetime();
+
+ *line = 0;
+ check_lpq_cache(snum);
+
+ if (!printername || !*printername) {
+ DEBUG(6,("xx 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);
- }
+ if (!lpq_command || !(*lpq_command)) {
+ DEBUG(5,("No lpq command\n"));
+ return(0);
+ }
- strcpy(syscmd,lpq_command);
- string_sub(syscmd,"%p",printername);
+ pstrcpy(syscmd,lpq_command);
+ string_sub(syscmd,"%p",printername);
- standard_sub(cnum,syscmd);
+ standard_sub(conn,syscmd);
- sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
+ slprintf(outfile,sizeof(outfile)-1, "%s/lpq.%08x",tmpdir(),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 (!lpq_cache_reset[snum] && cachetime && !sys_stat(outfile,&sbuf)) {
+ if (time(NULL) - sbuf.st_mtime < cachetime) {
+ DEBUG(3,("Using cached lpq output\n"));
+ dorun = False;
+ }
}
- }
- }
-
- if (dorun) {
- ret = smbrun(syscmd,outfile);
- DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
- }
- lpq_cache_reset[snum] = False;
+ if (dorun) {
+ ret = smbrun(syscmd,outfile,True);
+ DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+ }
- f = fopen(outfile,"r");
- if (!f) {
- if (lfd >= 0) file_unlock(lfd);
- return(0);
- }
+ lpq_cache_reset[snum] = False;
- 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;
+ f = fopen(outfile,"r");
+ if (!f) {
+ return(0);
}
- bzero((char *)&(*queue)[count],sizeof(**queue));
-
- /* parse it */
- if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
- continue;
+ if (status) {
+ fstrcpy(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));
- count++;
- }
-
- fclose(f);
-
- if (lfd >= 0) file_unlock(lfd);
-
- if (!cachetime)
- unlink(outfile);
- else
- chmod(outfile,0666);
- return(count);
+ /* parse it */
+ if (!parse_lpq_entry(snum,line,
+ &(*queue)[count],status,count==0))
+ continue;
+
+ count++;
+ }
+
+ fclose(f);
+
+ if (!cachetime) {
+ unlink(outfile);
+ } else {
+ /* we only expect this to succeed on trapdoor systems,
+ on normal systems the file is owned by root */
+ chmod(outfile,0666);
+ }
+ return(count);
}
/****************************************************************************
delete a printer queue entry
****************************************************************************/
-void del_printqueue(int cnum,int snum,int jobid)
+void del_printqueue(connection_struct *conn,int snum,int jobid)
{
char *lprm_command = lp_lprmcommand(snum);
char *printername = PRINTERNAME(snum);
@@ -806,14 +1138,14 @@ void del_printqueue(int cnum,int snum,int jobid)
return;
}
- sprintf(jobstr,"%d",jobid);
+ slprintf(jobstr,sizeof(jobstr)-1,"%d",jobid);
- strcpy(syscmd,lprm_command);
+ pstrcpy(syscmd,lprm_command);
string_sub(syscmd,"%p",printername);
string_sub(syscmd,"%j",jobstr);
- standard_sub(cnum,syscmd);
+ standard_sub(conn,syscmd);
- ret = smbrun(syscmd,NULL);
+ ret = smbrun(syscmd,NULL,False);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
lpq_reset(snum); /* queue has changed */
}
@@ -821,7 +1153,7 @@ void del_printqueue(int cnum,int snum,int jobid)
/****************************************************************************
change status of a printer queue entry
****************************************************************************/
-void status_printjob(int cnum,int snum,int jobid,int status)
+void status_printjob(connection_struct *conn,int snum,int jobid,int status)
{
char *lpstatus_command =
(status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
@@ -844,16 +1176,117 @@ void status_printjob(int cnum,int snum,int jobid,int status)
return;
}
- sprintf(jobstr,"%d",jobid);
+ slprintf(jobstr,sizeof(jobstr)-1,"%d",jobid);
- strcpy(syscmd,lpstatus_command);
+ pstrcpy(syscmd,lpstatus_command);
string_sub(syscmd,"%p",printername);
string_sub(syscmd,"%j",jobstr);
- standard_sub(cnum,syscmd);
+ standard_sub(conn,syscmd);
- ret = smbrun(syscmd,NULL);
+ ret = smbrun(syscmd,NULL,False);
DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
lpq_reset(snum); /* queue has changed */
}
+
+/****************************************************************************
+we encode print job numbers over the wire so that when we get them back we can
+tell not only what print job they are but also what service it belongs to,
+this is to overcome the problem that windows clients tend to send the wrong
+service number when doing print queue manipulation!
+****************************************************************************/
+int printjob_encode(int snum, int job)
+{
+ return ((snum&0xFF)<<8) | (job & 0xFF);
+}
+
+/****************************************************************************
+and now decode them again ...
+****************************************************************************/
+void printjob_decode(int jobid, int *snum, int *job)
+{
+ (*snum) = (jobid >> 8) & 0xFF;
+ (*job) = jobid & 0xFF;
+}
+
+/****************************************************************************
+ Change status of a printer queue
+****************************************************************************/
+
+void status_printqueue(connection_struct *conn,int snum,int status)
+{
+ char *queuestatus_command = (status==LPSTAT_STOPPED ?
+ lp_queuepausecommand(snum):lp_queueresumecommand(snum));
+ char *printername = PRINTERNAME(snum);
+ pstring syscmd;
+ 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 (!queuestatus_command || !(*queuestatus_command)) {
+ DEBUG(5,("No queuestatus command to %s job\n",
+ (status==LPSTAT_STOPPED?"pause":"resume")));
+ return;
+ }
+
+ pstrcpy(syscmd,queuestatus_command);
+ string_sub(syscmd,"%p",printername);
+ standard_sub(conn,syscmd);
+
+ ret = smbrun(syscmd,NULL,False);
+ DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+ lpq_reset(snum); /* queue has changed */
+}
+
+
+
+/***************************************************************************
+auto-load printer services
+***************************************************************************/
+static 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 = lp_auto_services();
+
+ if (!str) return;
+
+ printers = lp_servicenumber(PRINTERS_NAME);
+
+ if (printers < 0) 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);
+ }
+ }
+}
+
+/***************************************************************************
+load automatic printer services
+***************************************************************************/
+void load_printers(void)
+{
+ add_auto_printers();
+ if (lp_load_printers())
+ add_all_printers();
+}
diff --git a/source/rpc_client/cli_login.c b/source/rpc_client/cli_login.c
new file mode 100644
index 00000000000..abe471379ba
--- /dev/null
+++ b/source/rpc_client/cli_login.c
@@ -0,0 +1,191 @@
+/*
+ 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+
+/****************************************************************************
+Initialize domain session credentials.
+****************************************************************************/
+
+BOOL cli_nt_setup_creds(struct cli_state *cli, unsigned char mach_pwd[16])
+{
+ 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 False;
+ }
+
+ /**************** Long-term Session key **************/
+
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd, cli->sess_key);
+ bzero(cli->sess_key+8, 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.
+ */
+
+ if (!cli_net_auth2(cli, SEC_CHAN_WKSTA, 0x000001ff, &srv_chal))
+ {
+ DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed\n"));
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set machine password.
+ ****************************************************************************/
+
+BOOL cli_nt_srv_pwset(struct cli_state *cli, unsigned char *new_hashof_mach_pwd)
+{
+ unsigned char processed_new_pwd[16];
+
+ DEBUG(5,("cli_nt_login_interactive: %d\n", __LINE__));
+
+#ifdef DEBUG_PASSWORD
+ dump_data(6, new_hashof_mach_pwd, 16);
+#endif
+
+ /* Process the new password. */
+ cred_hash3( processed_new_pwd, new_hashof_mach_pwd, cli->sess_key, 1);
+
+ /* send client srv_pwset challenge */
+ return cli_net_srv_pwset(cli, processed_new_pwd);
+}
+
+#if UNUSED_CODE
+/****************************************************************************
+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.
+ ****************************************************************************/
+BOOL 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)
+{
+ unsigned char lm_owf_user_pwd[16];
+ unsigned char nt_owf_user_pwd[16];
+ BOOL ret;
+
+ DEBUG(5,("cli_nt_login_interactive: %d\n", __LINE__));
+
+ nt_lm_owf_gen(password, (char *)nt_owf_user_pwd, (char *)lm_owf_user_pwd);
+
+#ifdef DEBUG_PASSWORD
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, lm_owf_user_pwd, 16);
+
+ DEBUG(100,("nt owf of user password: "));
+ dump_data(100, 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. */
+ make_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;
+}
+#endif
+
+/****************************************************************************
+NT login - network.
+*ALWAYS* use this call to validate a user as it does not expose plaintext
+password equivalents over the network. JRA.
+****************************************************************************/
+
+BOOL cli_nt_login_network(struct cli_state *cli, char *domain, char *username,
+ uint32 smb_userid_low, char lm_chal[8], char lm_chal_resp[24],
+ char nt_chal_resp[24],
+ 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. */
+ make_id_info2(&ctr->auth.id2, domain, 0,
+ smb_userid_low, 0,
+ username, cli->clnt_name_slash,
+ (uchar *)lm_chal, (uchar *)lm_chal_resp, (uchar *)nt_chal_resp);
+
+ /* Send client sam-logon request - update credentials on success. */
+ return cli_net_sam_logon(cli, ctr, user_info3);
+}
+
+#if UNUSED_CODE
+/****************************************************************************
+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);
+}
+#endif
diff --git a/source/rpc_client/cli_lsarpc.c b/source/rpc_client/cli_lsarpc.c
new file mode 100644
index 00000000000..2f9952f5cb0
--- /dev/null
+++ b/source/rpc_client/cli_lsarpc.c
@@ -0,0 +1,255 @@
+
+/*
+ * 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.
+ */
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+do a LSA Open Policy
+****************************************************************************/
+BOOL do_lsa_open_policy(struct cli_state *cli,
+ char *server_name, POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ LSA_Q_OPEN_POL q_o;
+ BOOL valid_pol = False;
+
+ if (hnd == NULL) return False;
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0 , 4, SAFETY_MARGIN, True );
+
+ /* create and send a MSRPC command with api LSA_OPENPOLICY */
+
+ DEBUG(4,("LSA Open Policy\n"));
+
+ /* store the parameters */
+ make_q_open_pol(&q_o, server_name, 0, 0, 0x1);
+
+ /* turn parameters into data stream */
+ lsa_io_q_open_pol("", &q_o, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, LSA_OPENPOLICY, &buf, &rbuf))
+ {
+ LSA_R_OPEN_POL r_o;
+ BOOL p;
+
+ lsa_io_r_open_pol("", &r_o, &rbuf, 0);
+ p = rbuf.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_OPENPOLICY: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. return the policy handle */
+ memcpy(hnd, r_o.pol.data, sizeof(hnd->data));
+ valid_pol = True;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return valid_pol;
+}
+
+/****************************************************************************
+do a LSA Query Info Policy
+****************************************************************************/
+BOOL do_lsa_query_info_pol(struct cli_state *cli,
+ POLICY_HND *hnd, uint16 info_class,
+ fstring domain_name, fstring domain_sid)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ LSA_Q_QUERY_INFO q_q;
+ BOOL valid_response = False;
+
+ if (hnd == NULL || domain_name == NULL || domain_sid == NULL) return False;
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0 , 4, SAFETY_MARGIN, True );
+
+ /* create and send a MSRPC command with api LSA_QUERYINFOPOLICY */
+
+ DEBUG(4,("LSA Query Info Policy\n"));
+
+ /* store the parameters */
+ make_q_query(&q_q, hnd, info_class);
+
+ /* turn parameters into data stream */
+ lsa_io_q_query("", &q_q, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, LSA_QUERYINFOPOLICY, &buf, &rbuf))
+ {
+ LSA_R_QUERY_INFO r_q;
+ BOOL p;
+
+ lsa_io_r_query("", &r_q, &rbuf, 0);
+ p = rbuf.offset != 0;
+
+ if (p && r_q.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_QUERYINFOPOLICY: %s\n", get_nt_error_msg(r_q.status)));
+ p = False;
+ }
+
+ if (p && r_q.info_class != q_q.info_class)
+ {
+ /* report different info classes */
+ DEBUG(0,("LSA_QUERYINFOPOLICY: error info_class (q,r) differ - (%x,%x)\n",
+ q_q.info_class, r_q.info_class));
+ p = False;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ switch (r_q.info_class)
+ {
+ case 3:
+ {
+ char *dom_name = unistrn2(r_q.dom.id3.uni_domain_name.buffer,
+ r_q.dom.id3.uni_domain_name.uni_str_len);
+ fstrcpy(domain_name, dom_name);
+ sid_to_string(domain_sid, &(r_q.dom.id3.dom_sid.sid));
+
+ valid_response = True;
+ break;
+ }
+ case 5:
+ {
+ char *dom_name = unistrn2(r_q.dom.id5.uni_domain_name.buffer,
+ r_q.dom.id5.uni_domain_name.uni_str_len);
+ fstrcpy(domain_name, dom_name);
+ sid_to_string(domain_sid, &(r_q.dom.id5.dom_sid.sid));
+
+ valid_response = True;
+ break;
+ }
+ default:
+ {
+ DEBUG(3,("LSA_QUERYINFOPOLICY: unknown info class\n"));
+ domain_name[0] = 0;
+ domain_sid [0] = 0;
+
+ break;
+ }
+ }
+ DEBUG(3,("LSA_QUERYINFOPOLICY (level %x): domain:%s domain sid:%s\n",
+ r_q.info_class, domain_name, domain_sid));
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return valid_response;
+}
+
+/****************************************************************************
+do a LSA Close
+****************************************************************************/
+BOOL do_lsa_close(struct cli_state *cli, POLICY_HND *hnd)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ LSA_Q_CLOSE q_c;
+ BOOL valid_close = False;
+
+ if (hnd == NULL) return False;
+
+ /* create and send a MSRPC command with api LSA_OPENPOLICY */
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("LSA Close\n"));
+
+ /* store the parameters */
+ make_lsa_q_close(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ lsa_io_q_close("", &q_c, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, LSA_CLOSE, &buf, &rbuf))
+ {
+ LSA_R_CLOSE r_c;
+ BOOL p;
+
+ lsa_io_r_close("", &r_c, &rbuf, 0);
+ p = rbuf.offset != 0;
+
+ if (p && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("LSA_CLOSE: %s\n", get_nt_error_msg(r_c.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ /* check that the returned policy handle is all zeros */
+ int i;
+ valid_close = True;
+
+ for (i = 0; i < sizeof(r_c.pol.data); i++)
+ {
+ if (r_c.pol.data[i] != 0)
+ {
+ valid_close = False;
+ break;
+ }
+ }
+ if (!valid_close)
+ {
+ DEBUG(0,("LSA_CLOSE: non-zero handle returned\n"));
+ }
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return valid_close;
+}
+
+
diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c
new file mode 100644
index 00000000000..9af2a05f27c
--- /dev/null
+++ b/source/rpc_client/cli_netlogon.c
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ */
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+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, uint32 status_level)
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ NET_Q_LOGON_CTRL2 q_l;
+ BOOL ok = False;
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0, 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_q_logon_ctrl2(&q_l, cli->srv_name_slash, status_level);
+
+ /* turn parameters into data stream */
+ net_io_q_logon_ctrl2("", &q_l, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
+ {
+ NET_R_LOGON_CTRL2 r_l;
+
+ net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
+ ok = (rbuf.offset != 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(&rbuf);
+ prs_mem_free(&buf );
+
+ 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.
+****************************************************************************/
+
+BOOL 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;
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0, 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_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 */
+ net_io_q_auth_2("", &q_a, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
+ {
+ NET_R_AUTH_2 r_a;
+
+ net_io_r_auth_2("", &r_a, &rbuf, 0);
+ ok = (rbuf.offset != 0);
+
+ if (ok && r_a.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_auth2: Error %s\n", get_nt_error_msg(r_a.status)));
+ cli->nt_error = r_a.status;
+ 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 (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;
+ }
+
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return ok;
+}
+
+/****************************************************************************
+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;
+
+ if (srv_chal == NULL || clnt_chal == NULL)
+ return False;
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0, 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_q_req_chal(&q_c, cli->srv_name_slash, global_myname, clnt_chal);
+
+ /* turn parameters into data stream */
+ net_io_q_req_chal("", &q_c, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
+ {
+ NET_R_REQ_CHAL r_c;
+ BOOL ok;
+
+ net_io_r_req_chal("", &r_c, &rbuf, 0);
+ ok = (rbuf.offset != 0);
+
+ if (ok && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_req_chal: Error %s\n", get_nt_error_msg(r_c.status)));
+ cli->nt_error = 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(&rbuf);
+ prs_mem_free(&buf );
+
+ return valid_chal;
+}
+
+/***************************************************************************
+LSA Server Password Set.
+****************************************************************************/
+
+BOOL cli_net_srv_pwset(struct cli_state *cli, uint8 hashed_mach_pwd[16])
+{
+ prs_struct rbuf;
+ prs_struct buf;
+ DOM_CRED new_clnt_cred;
+ NET_Q_SRV_PWSET q_s;
+ BOOL ok = False;
+ uint16 sec_chan_type = 2;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0, 4, SAFETY_MARGIN, True );
+
+ /* create and send a MSRPC command with api NET_SRV_PWSET */
+
+ DEBUG(4,("cli_net_srv_pwset: 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_q_srv_pwset(&q_s, cli->srv_name_slash, cli->mach_acct, sec_chan_type,
+ global_myname, &new_clnt_cred, (char *)hashed_mach_pwd);
+
+ /* turn parameters into data stream */
+ net_io_q_srv_pwset("", &q_s, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SRVPWSET, &buf, &rbuf))
+ {
+ NET_R_SRV_PWSET r_s;
+
+ net_io_r_srv_pwset("", &r_s, &rbuf, 0);
+ ok = (rbuf.offset != 0);
+
+ if (ok && r_s.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_srv_pwset: %s\n", get_nt_error_msg(r_s.status)));
+ cli->nt_error = r_s.status;
+ ok = False;
+ }
+
+ /* Update the credentials. */
+ if (ok && !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 ));
+ ok = False;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return ok;
+}
+
+/***************************************************************************
+LSA SAM Logon - interactive or network.
+****************************************************************************/
+
+BOOL cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
+ NET_USER_INFO_3 *user_info3)
+{
+ DOM_CRED new_clnt_cred;
+ DOM_CRED dummy_rtn_creds;
+ prs_struct rbuf;
+ prs_struct buf;
+ uint16 validation_level = 3;
+ NET_Q_SAM_LOGON q_s;
+ BOOL ok = False;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0, 4, SAFETY_MARGIN, True );
+
+ /* create and send a MSRPC command with api NET_SAMLOGON */
+
+ DEBUG(4,("cli_net_sam_logon: 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));
+
+ /* store the parameters */
+ make_sam_info(&(q_s.sam_id), cli->srv_name_slash, global_myname,
+ &new_clnt_cred, &dummy_rtn_creds, ctr->switch_value, ctr, validation_level);
+
+ /* turn parameters into data stream */
+ net_io_q_sam_logon("", &q_s, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SAMLOGON, &buf, &rbuf))
+ {
+ NET_R_SAM_LOGON r_s;
+
+ r_s.user = user_info3;
+
+ net_io_r_sam_logon("", &r_s, &rbuf, 0);
+ ok = (rbuf.offset != 0);
+
+ if (ok && r_s.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_sam_logon: %s\n", get_nt_error_msg(r_s.status)));
+ cli->nt_error = 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_logon: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ ok = False;
+ }
+
+ if (ok && r_s.switch_value != 3)
+ {
+ /* report different switch_value */
+ DEBUG(0,("cli_net_sam_logon: switch_value of 3 expected %x\n",
+ r_s.switch_value));
+ ok = False;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return ok;
+}
+
+#if UNUSED_CODE
+/***************************************************************************
+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;
+ uint16 validation_level = 3;
+ BOOL ok = False;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0, 4, SAFETY_MARGIN, True );
+
+ /* 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));
+
+ /* store the parameters */
+ make_sam_info(&(q_s.sam_id), cli->srv_name_slash, global_myname,
+ &new_clnt_cred, &dummy_rtn_creds, ctr->switch_value, ctr, validation_level);
+
+ /* turn parameters into data stream */
+ net_io_q_sam_logoff("", &q_s, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
+ {
+ NET_R_SAM_LOGOFF r_s;
+
+ net_io_r_sam_logoff("", &r_s, &rbuf, 0);
+ ok = (rbuf.offset != 0);
+
+ if (ok && r_s.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_sam_logoff: %s\n", get_nt_error_msg(r_s.status)));
+ cli->nt_error = 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(&rbuf);
+ prs_mem_free(&buf );
+
+ return ok;
+}
+#endif
+
+/*********************************************************
+ Change the domain password on the PDC.
+**********************************************************/
+
+static BOOL modify_trust_password( char *domain, char *remote_machine,
+ unsigned char orig_trust_passwd_hash[16],
+ unsigned char new_trust_passwd_hash[16])
+{
+ struct cli_state cli;
+ struct nmb_name calling, called;
+
+ ZERO_STRUCT(cli);
+ if(cli_initialise(&cli) == False) {
+ DEBUG(0,("modify_trust_password: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("modify_trust_password: Can't resolve address for %s\n", remote_machine));
+ return False;
+ }
+
+ if (ismyip(cli.dest_ip)) {
+ DEBUG(0,("modify_trust_password: Machine %s is one of our addresses. Cannot add \
+to ourselves.\n", remote_machine));
+ return False;
+ }
+
+ if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("modify_trust_password: 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 , scope);
+ make_nmb_name(&called , remote_machine, 0x20, scope);
+
+ if (!cli_session_request(&cli, &calling, &called))
+ {
+ DEBUG(0,("modify_trust_password: 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)) {
+ DEBUG(0,("modify_trust_password: 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,("modify_trust_password: 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,("modify_trust_password: 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,("modify_trust_password: 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,("modify_trust_password: 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_NETLOGON, False) == 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 False;
+ }
+
+ if(cli_nt_setup_creds(&cli, orig_trust_passwd_hash) == False) {
+ DEBUG(0,("modify_trust_password: unable to setup the PDC credentials 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;
+ }
+
+ if( cli_nt_srv_pwset( &cli,new_trust_passwd_hash ) == False) {
+ DEBUG(0,("modify_trust_password: unable to change password for machine %s in domain \
+%s to Domain controller %s. Error was %s.\n", global_myname, domain, remote_machine,
+ cli_errstr(&cli)));
+ cli_close(&cli, cli.nt_pipe_fnum);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+
+ return True;
+}
+
+/************************************************************************
+ Change the trust account password for a domain.
+ The user of this function must have locked the trust password file for
+ update.
+************************************************************************/
+
+BOOL change_trust_account_password( char *domain, char *remote_machine_list)
+{
+ fstring remote_machine;
+ unsigned char old_trust_passwd_hash[16];
+ unsigned char new_trust_passwd_hash[16];
+ time_t lct;
+
+ if(!get_trust_account_password( old_trust_passwd_hash, &lct)) {
+ DEBUG(0,("change_trust_account_password: unable to read the machine \
+account password for domain %s.\n", domain));
+ return False;
+ }
+
+ /*
+ * Create the new (random) password.
+ */
+ generate_random_buffer( new_trust_passwd_hash, 16, True);
+
+ while(remote_machine_list &&
+ next_token(&remote_machine_list, remote_machine,
+ LIST_SEP, sizeof(remote_machine))) {
+ strupper(remote_machine);
+ if(modify_trust_password( domain, remote_machine,
+ old_trust_passwd_hash, new_trust_passwd_hash)) {
+ DEBUG(0,("%s : change_trust_account_password: Changed password for \
+domain %s.\n", timestring(), domain));
+ /*
+ * Return the result of trying to write the new password
+ * back into the trust account file.
+ */
+ return set_trust_account_password(new_trust_passwd_hash);
+ }
+ }
+
+ DEBUG(0,("%s : change_trust_account_password: Failed to change password for \
+domain %s.\n", timestring(), domain));
+ return False;
+}
diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c
new file mode 100644
index 00000000000..1689ae0e696
--- /dev/null
+++ b/source/rpc_client/cli_pipe.c
@@ -0,0 +1,699 @@
+
+/*
+ * 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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 SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+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 = 1;
+ return ++call_id;
+}
+
+/*******************************************************************
+ uses SMBreadX to get rest of rpc data
+ ********************************************************************/
+
+static BOOL rpc_read(struct cli_state *cli,
+ prs_struct *rdata, uint32 data_to_read,
+ uint32 rdata_offset)
+{
+ int size = 0x1630;
+ int file_offset = rdata_offset;
+ int num_read;
+ char *data = rdata->data->data;
+ uint32 err;
+ uint32 errclass;
+ uint32 new_data_size = rdata->data->data_used + data_to_read;
+
+ data += rdata_offset;
+
+ file_offset -= rdata_offset;
+
+ DEBUG(5,("rpc_read: data_to_read: %d data offset: %d file offset: %d\n",
+ data_to_read, rdata_offset, file_offset));
+
+ if (new_data_size > rdata->data->data_size)
+ {
+ mem_grow_data(&rdata->data, True, new_data_size, True);
+ DEBUG(5,("rpc_read: grow buffer to %d\n", rdata->data->data_used));
+ }
+
+ do /* read data using SMBreadX */
+ {
+ if (size > data_to_read)
+ size = data_to_read;
+
+ new_data_size = rdata->data->data_used + size;
+
+ if (new_data_size > rdata->data->data_size)
+ {
+ mem_grow_data(&rdata->data, True, new_data_size, True);
+ DEBUG(5,("rpc_read: grow buffer to %d\n", rdata->data->data_used));
+ }
+
+ num_read = cli_read(cli, cli->nt_pipe_fnum, data, file_offset + 0x100000, size);
+
+ DEBUG(5,("rpc_read: read offset: %d read: %d to read: %d\n",
+ file_offset, num_read, data_to_read));
+
+ data_to_read -= num_read;
+ file_offset += num_read;
+ data += num_read;
+
+ cli_error(cli, (int *)&errclass, (int *)&err);
+ if (errclass != 0)
+ return False;
+
+ } while (num_read > 0 && data_to_read > 0);
+ /* && err == (0x80000000 | STATUS_BUFFER_OVERFLOW)); */
+
+ mem_realloc_data(rdata->data, file_offset + rdata_offset);
+ rdata->data->offset.end = file_offset + rdata_offset;
+
+ DEBUG(5,("rpc_read: data supposedly left to read:0x%x\n", data_to_read));
+
+ return data_to_read == 0;
+}
+
+/****************************************************************************
+ checks the header
+ ****************************************************************************/
+static BOOL rpc_check_hdr(prs_struct *rdata, uint8 *pkt_type,
+ BOOL *first, BOOL *last, int *len)
+{
+ RPC_HDR rhdr;
+
+ DEBUG(5,("rpc_check_hdr: rdata->data->data_used: %d\n", rdata->data->data_used));
+
+ smb_io_rpc_hdr ("rpc_hdr ", &rhdr , rdata, 0);
+
+ if (!rdata->offset || rdata->offset != 0x10)
+ {
+ DEBUG(0,("cli_pipe: error in rpc header\n"));
+ return False;
+ }
+
+ DEBUG(5,("rpc_check_hdr: (after smb_io_rpc_hdr call) rdata->data->data_used: %d\n",
+ rdata->data->data_used));
+
+ (*first ) = IS_BITS_SET_ALL(rhdr.flags, RPC_FLG_FIRST);
+ (*last ) = IS_BITS_SET_ALL(rhdr.flags, RPC_FLG_LAST );
+ (*len ) = rhdr.frag_len - rdata->data->data_used;
+ (*pkt_type) = rhdr.pkt_type;
+
+ 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.
+
+ [note: from a data abstraction viewpoint, this function is marginally
+ complicated by the return side of cli_api_pipe getting in the way
+ (i.e, the SMB header stuff). the proper way to do this is to split
+ cli_api_pipe down into receive / transmit. oh, and split cli_readx
+ down. in other words, state-based (kernel) techniques...]
+
+ ****************************************************************************/
+
+static BOOL rpc_api_pipe(struct cli_state *cli, uint16 cmd,
+ prs_struct *param , prs_struct *data,
+ prs_struct *rparam, prs_struct *rdata)
+{
+ int len;
+
+ uint16 setup[2]; /* only need 2 uint16 setup parameters */
+ uint32 err;
+ uint32 errclass;
+ uint8 pkt_type = 0xff;
+ BOOL first = True;
+ BOOL last = True;
+
+ /*
+ * Setup the pointers from the incoming.
+ */
+ char *pparams = param ? param->data->data : NULL;
+ int params_len = param ? param->data->data_used : 0;
+ char *pdata = data ? data->data->data : NULL;
+ int data_len = data ? data->data->data_used : 0;
+
+ /*
+ * Setup the pointers to the outgoing.
+ */
+ char **pp_ret_params = rparam ? &rparam->data->data : NULL;
+ uint32 *p_ret_params_len = rparam ? &rparam->data->data_used : NULL;
+
+ char **pp_ret_data = rdata ? &rdata->data->data : NULL;
+ uint32 *p_ret_data_len = rdata ? &rdata->data->data_used : NULL;
+
+ /* create setup parameters. */
+ setup[0] = cmd;
+ setup[1] = cli->nt_pipe_fnum; /* pipe file handle. got this from an SMBOpenX. */
+
+ /* send the data: receive a response. */
+ if (!cli_api_pipe(cli, "\\PIPE\\\0\0\0", 8,
+ setup, 2, 0, /* Setup, length, max */
+ pparams, params_len, 0, /* Params, length, max */
+ pdata, data_len, 1024, /* data, length, max */
+ pp_ret_params, p_ret_params_len, /* return params, len */
+ pp_ret_data, p_ret_data_len)) /* return data, len */
+ {
+ DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli)));
+ return False;
+ }
+
+ if (rdata->data->data == NULL)
+ return False;
+
+ /**** parse the header: check it's a response record */
+
+ rdata->data->offset.start = 0;
+ rdata->data->offset.end = rdata->data->data_used;
+ rdata->offset = 0;
+
+ /* cli_api_pipe does an ordinary Realloc - we have no margins now. */
+ rdata->data->margin = 0;
+ if(rparam)
+ rparam->data->margin = 0;
+
+ if (!rpc_check_hdr(rdata, &pkt_type, &first, &last, &len))
+ return False;
+
+ if (pkt_type == RPC_RESPONSE)
+ {
+ RPC_HDR_RESP rhdr_resp;
+ smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0);
+ }
+
+ DEBUG(5,("rpc_api_pipe: len left: %d smbtrans read: %d\n",
+ len, rdata->data->data_used));
+
+ /* check if data to be sent back was too large for one SMB. */
+ /* err status is only informational: the _real_ check is on the length */
+ if (len > 0) /* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */
+ {
+ if (!rpc_read(cli, rdata, len, rdata->data->data_used))
+ return False;
+ }
+
+ /* 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;
+ }
+
+ while (!last) /* read more fragments until we get the last one */
+ {
+ RPC_HDR rhdr;
+ RPC_HDR_RESP rhdr_resp;
+ int num_read;
+ prs_struct hps;
+
+ prs_init(&hps, 0x18, 4, 0, True);
+
+ num_read = cli_read(cli, cli->nt_pipe_fnum, hps.data->data, 0, 0x18);
+ DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read));
+
+ if (num_read != 0x18)
+ return False;
+
+ smb_io_rpc_hdr ("rpc_hdr ", &rhdr , &hps, 0);
+ smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0);
+
+ prs_mem_free(&hps);
+
+ cli_error(cli, (int *)&errclass, (int *)&err);
+ if (errclass != 0)
+ return False;
+
+ first = IS_BITS_SET_ALL(rhdr.flags, RPC_FLG_FIRST);
+ last = IS_BITS_SET_ALL(rhdr.flags, RPC_FLG_LAST );
+
+ if (first)
+ {
+ DEBUG(0,("rpc_api_pipe: wierd rpc header received\n"));
+ return False;
+ }
+
+ len = rhdr.frag_len - hps.offset;
+ if (!rpc_read(cli, rdata, len, rdata->data->data_used))
+ return False;
+ }
+
+ 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 *rhdr,
+ prs_struct *rhdr_rb,
+ prs_struct *auth_req,
+ RPC_IFACE *abstract, RPC_IFACE *transfer,
+ char *my_name, char *domain)
+{
+ RPC_HDR_RB hdr_rb;
+ RPC_HDR hdr;
+ RPC_AUTH_NTLMSSP_REQ ntlmssp_req;
+
+ /* create the bind request RPC_HDR_RB */
+ make_rpc_hdr_rb(&hdr_rb, 0x1630, 0x1630, 0x0,
+ 0x1, 0x0, 0x1, abstract, transfer);
+
+ /* stream the bind request data */
+ smb_io_rpc_hdr_rb("", &hdr_rb, rhdr_rb, 0);
+ mem_realloc_data(rhdr_rb->data, rhdr_rb->offset);
+
+ if (auth_req != NULL)
+ {
+ /*
+ * I have a feeling this is broken right now... JRA.
+ */
+ make_rpc_auth_ntlmssp_req(&ntlmssp_req, "NTLMSSP", 0x1,
+ 0x0000b2b3, my_name, domain);
+ smb_io_rpc_auth_ntlmssp_req("", &ntlmssp_req, auth_req, 0);
+ mem_realloc_data(auth_req->data, auth_req->offset);
+ }
+
+ /* create the request RPC_HDR */
+ make_rpc_hdr(&hdr, RPC_BIND, 0x0, get_rpc_call_id(),
+ rhdr_rb->offset, auth_req != NULL ? auth_req->offset : 0);
+
+ smb_io_rpc_hdr("hdr" , &hdr , rhdr, 0);
+ mem_realloc_data(rhdr->data, rhdr->offset);
+
+ if (rhdr->data == NULL || rhdr_rb->data == NULL)
+ return False;
+
+ /***/
+ /*** link rpc header, bind acknowledgment and authentication responses ***/
+ /***/
+
+ rhdr->data->offset.start = 0;
+ rhdr->data->offset.end = rhdr->offset;
+ rhdr->data->next = rhdr_rb->data;
+
+ if (auth_req != NULL)
+ {
+ rhdr_rb->data->offset.start = rhdr->offset;
+ rhdr_rb->data->offset.end = rhdr->offset + rhdr_rb->offset;
+ rhdr_rb->data->next = auth_req->data;
+
+ auth_req->data->offset.start = rhdr->offset + rhdr_rb->offset;
+ auth_req->data->offset.end = rhdr->offset + auth_req->offset + rhdr_rb->offset;
+ auth_req->data->next = NULL;
+ }
+ else
+ {
+ rhdr_rb->data->offset.start = rhdr->offset;
+ rhdr_rb->data->offset.end = rhdr->offset + rhdr_rb->offset;
+ rhdr_rb->data->next = NULL;
+ }
+
+ 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_request(prs_struct *rhdr, uint8 op_num, int data_len)
+{
+ RPC_HDR_REQ hdr_req;
+ RPC_HDR hdr;
+
+ DEBUG(5,("create_rpc_request: opnum: 0x%x data_len: 0x%x\n",
+ op_num, data_len));
+
+ /* create the rpc header RPC_HDR */
+ make_rpc_hdr(&hdr , RPC_REQUEST, RPC_FLG_FIRST | RPC_FLG_LAST,
+ get_rpc_call_id(), data_len + 0x18, 0);
+
+ /* create the rpc request RPC_HDR_REQ */
+ make_rpc_hdr_req(&hdr_req, data_len, op_num);
+
+ /* stream-time... */
+ smb_io_rpc_hdr ("hdr ", &hdr , rhdr, 0);
+ smb_io_rpc_hdr_req("hdr_req", &hdr_req, rhdr, 0);
+
+ if (rhdr->data == NULL || rhdr->offset != 0x18)
+ return False;
+
+ rhdr->data->offset.start = 0;
+ rhdr->data->offset.end = rhdr->offset;
+
+ 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)
+{
+ /* fudge this, at the moment: create the header; memcpy the data. oops. */
+ prs_struct rparam;
+ prs_struct hdr;
+ int data_len;
+ BOOL ret;
+
+ data_len = data->offset + 0x18;
+ data->data->offset.end = data->offset;
+
+ prs_init(&hdr , data_len, 4, SAFETY_MARGIN, False);
+ prs_init(&rparam, 0 , 4, 0 , True );
+
+ create_rpc_request(&hdr, op_num, data_len);
+
+ mem_realloc_data(hdr.data, data_len);
+ hdr.data->offset.end = data_len;
+ mem_buf_copy(mem_data(&(hdr.data), 0x18), data->data, 0, data->offset);
+
+ ret = rpc_api_pipe(cli, 0x0026, NULL, &hdr, &rparam, rdata);
+
+ prs_mem_free(&rparam);
+ prs_mem_free(&hdr);
+
+ return ret;
+}
+
+
+/****************************************************************************
+do an rpc bind
+****************************************************************************/
+
+static BOOL rpc_pipe_set_hnd_state(struct cli_state *cli, 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\\\0\0\0", 8,
+ 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;
+ }
+
+ if(rparam)
+ free(rparam);
+ if(rdata)
+ free(rdata);
+
+ return state_set;
+}
+
+/****************************************************************************
+ check the rpc bind acknowledge response
+****************************************************************************/
+
+static BOOL valid_pipe_name(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 */
+ memcpy(transfer, &(pipe_names[pipe_idx].trans_syntax),
+ sizeof(pipe_names[pipe_idx].trans_syntax));
+ memcpy(abstract, &(pipe_names[pipe_idx].abstr_syntax),
+ sizeof(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, char *pipe_name, RPC_IFACE *transfer)
+{
+ int i = 0;
+
+ while ((pipe_names[i].client_pipe != NULL))
+ {
+ DEBUG(6,("bind_rpc_pipe: searching pipe name: client:%s server:%s\n",
+ pipe_names[i].client_pipe , pipe_names[i].server_pipe ));
+
+ 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(2,("bind_rpc_pipe: pipe_name %s != expected pipe %s\n",
+ pipe_names[i].server_pipe , hdr_ba->addr.str));
+ return False;
+ }
+ }
+ 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.data, transfer->data,
+ sizeof(transfer->version)) ==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;
+}
+
+/****************************************************************************
+do an rpc bind
+****************************************************************************/
+
+static BOOL rpc_pipe_bind(struct cli_state *cli, char *pipe_name,
+ RPC_IFACE *abstract, RPC_IFACE *transfer, BOOL ntlmssp_auth)
+{
+ prs_struct hdr;
+ prs_struct hdr_rb;
+ prs_struct auth_req;
+ prs_struct data;
+ prs_struct rdata;
+ prs_struct rparam;
+
+ BOOL valid_ack = False;
+
+ if (pipe_name == NULL || abstract == NULL || transfer == NULL)
+ return False;
+
+ 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(&hdr , 0x10 , 4, 0x0 , False);
+ prs_init(&hdr_rb , 1024 , 4, SAFETY_MARGIN, False);
+ prs_init(&auth_req, ntlmssp_auth ? 1024 : 0, 4, SAFETY_MARGIN, False);
+
+ prs_init(&rdata , 0 , 4, SAFETY_MARGIN, True );
+ prs_init(&rparam, 0 , 4, SAFETY_MARGIN, True );
+
+ create_rpc_bind_req(&hdr, &hdr_rb, ntlmssp_auth ? &auth_req : NULL,
+ abstract, transfer, global_myname, global_myworkgroup);
+
+ /* this is a hack due to limitations in rpc_api_pipe */
+ prs_init(&data, mem_buf_len(hdr.data), 4, 0x0, False);
+ mem_buf_copy(data.data->data, hdr.data, 0, mem_buf_len(hdr.data));
+
+ /* send data on \PIPE\. receive a response */
+ if (rpc_api_pipe(cli, 0x0026, NULL, &data, &rparam, &rdata))
+ {
+ RPC_HDR_BA hdr_ba;
+
+ DEBUG(5, ("rpc_api_pipe: return OK\n"));
+
+ smb_io_rpc_hdr_ba("", &hdr_ba, &rdata, 0);
+
+ if (rdata.offset != 0)
+ valid_ack = check_bind_response(&hdr_ba, pipe_name, transfer);
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&hdr );
+ prs_mem_free(&hdr_rb );
+ prs_mem_free(&auth_req);
+ prs_mem_free(&rdata );
+ prs_mem_free(&rparam );
+
+ return valid_ack;
+}
+
+/****************************************************************************
+ open a session
+ ****************************************************************************/
+
+BOOL cli_nt_session_open(struct cli_state *cli, char *pipe_name, BOOL encrypted)
+{
+ RPC_IFACE abstract;
+ RPC_IFACE transfer;
+ int fnum;
+
+ /******************* open the pipe *****************/
+ 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, &abstract, &transfer, encrypted))
+ {
+ 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);
+}
diff --git a/source/rpc_client/cli_samr.c b/source/rpc_client/cli_samr.c
new file mode 100644
index 00000000000..ef20a999df5
--- /dev/null
+++ b/source/rpc_client/cli_samr.c
@@ -0,0 +1,705 @@
+/*
+ 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.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+
+
+/****************************************************************************
+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);
+}
+
+/****************************************************************************
+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;
+
+ bzero(usr, 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);
+}
+
+/****************************************************************************
+do a SAMR unknown 0x8 command
+****************************************************************************/
+BOOL do_samr_unknown_8(struct cli_state *cli,
+ POLICY_HND *domain_pol, uint16 switch_value)
+{
+ prs_struct data;
+ prs_struct rdata;
+
+ SAMR_Q_UNKNOWN_8 q_e;
+ BOOL valid_un8 = False;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Unknown 8 switch:%d\n", switch_value));
+
+ if (domain_pol == NULL) return False;
+
+ /* store the parameters */
+ make_samr_q_unknown_8(&q_e, domain_pol, switch_value);
+
+ /* turn parameters into data stream */
+ samr_io_q_unknown_8("", &q_e, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_UNKNOWN_8, &data, &rdata))
+ {
+#if 0
+
+ SAMR_R_UNKNOWN_8 r_e;
+ BOOL p;
+
+ samr_io_r_unknown_8("", &r_e, &rdata, 0);
+
+ p = rdata.offset != 0;
+ if (p && r_e.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_UNKNOWN_8: %s\n", get_nt_error_msg(r_e.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ valid_un8 = True;
+ }
+#endif
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_un8;
+}
+
+/****************************************************************************
+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;
+ BOOL valid_pol = False;
+
+ /* create and send a MSRPC command with api SAMR_ENUM_DOM_USERS */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Enum SAM DB max size:%x\n", size));
+
+ if (pol == NULL || num_sam_users == NULL) return False;
+
+ /* store the parameters */
+ make_samr_q_enum_dom_users(&q_e, pol,
+ num_entries, unk_0,
+ acb_mask, unk_1, size);
+
+ /* turn parameters into data stream */
+ samr_io_q_enum_dom_users("", &q_e, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_ENUM_DOM_USERS, &data, &rdata))
+ {
+ SAMR_R_ENUM_DOM_USERS r_e;
+ BOOL p;
+
+ samr_io_r_enum_dom_users("", &r_e, &rdata, 0);
+
+ p = rdata.offset != 0;
+ if (p && r_e.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_ENUM_DOM_USERS: %s\n", get_nt_error_msg(r_e.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ int i;
+ int name_idx = 0;
+
+ *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 = 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
+ {
+ bzero((*sam)[i].acct_name, 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));
+ }
+ valid_pol = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_pol;
+}
+
+/****************************************************************************
+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;
+ BOOL valid_pol = False;
+
+ /* create and send a MSRPC command with api SAMR_CONNECT */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Open Policy server:%s undoc value:%x\n",
+ srv_name, unknown_0));
+
+ if (srv_name == NULL || connect_pol == NULL) return False;
+
+ /* store the parameters */
+ make_samr_q_connect(&q_o, srv_name, unknown_0);
+
+ /* turn parameters into data stream */
+ samr_io_q_connect("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_CONNECT, &data, &rdata))
+ {
+ SAMR_R_CONNECT r_o;
+ BOOL p;
+
+ samr_io_r_connect("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_CONNECT: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ memcpy(connect_pol, &r_o.connect_pol, sizeof(r_o.connect_pol));
+ valid_pol = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_pol;
+}
+
+/****************************************************************************
+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;
+ BOOL valid_pol = False;
+
+ /* create and send a MSRPC command with api SAMR_OPEN_USER */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Open User. unk_0: %08x RID:%x\n",
+ unk_0, rid));
+
+ if (pol == NULL || user_pol == NULL) return False;
+
+ /* store the parameters */
+ make_samr_q_open_user(&q_o, pol, unk_0, rid);
+
+ /* turn parameters into data stream */
+ samr_io_q_open_user("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_OPEN_USER, &data, &rdata))
+ {
+ SAMR_R_OPEN_USER r_o;
+ BOOL p;
+
+ samr_io_r_open_user("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_OPEN_USER: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ memcpy(user_pol, &r_o.user_pol, sizeof(r_o.user_pol));
+ valid_pol = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_pol;
+}
+
+/****************************************************************************
+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)
+{
+ pstring sid_str;
+ prs_struct data;
+ prs_struct rdata;
+
+ SAMR_Q_OPEN_DOMAIN q_o;
+ BOOL valid_pol = False;
+
+ /* create and send a MSRPC command with api SAMR_OPEN_DOMAIN */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ sid_to_string(sid_str, sid);
+ DEBUG(4,("SAMR Open Domain. SID:%s RID:%x\n", sid_str, rid));
+
+ if (connect_pol == NULL || sid == NULL || domain_pol == NULL) return False;
+
+ /* store the parameters */
+ make_samr_q_open_domain(&q_o, connect_pol, rid, sid);
+
+ /* turn parameters into data stream */
+ samr_io_q_open_domain("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_OPEN_DOMAIN, &data, &rdata))
+ {
+ SAMR_R_OPEN_DOMAIN r_o;
+ BOOL p;
+
+ samr_io_r_open_domain("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_OPEN_DOMAIN: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ memcpy(domain_pol, &r_o.domain_pol, sizeof(r_o.domain_pol));
+ valid_pol = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_pol;
+}
+
+/****************************************************************************
+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_UNKNOWN_12 q_o;
+ BOOL valid_query = False;
+
+ /* create and send a MSRPC command with api SAMR_UNKNOWN_12 */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Query Unknown 12.\n"));
+
+ if (pol == NULL || rid == 0 || num_gids == 0 || gids == NULL ||
+ num_aliases == NULL || als_names == NULL || num_als_users == NULL ) return False;
+
+ /* store the parameters */
+ make_samr_q_unknown_12(&q_o, pol, rid, num_gids, gids);
+
+ /* turn parameters into data stream */
+ samr_io_q_unknown_12("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_UNKNOWN_12, &data, &rdata))
+ {
+ SAMR_R_UNKNOWN_12 r_o;
+ BOOL p;
+
+ samr_io_r_unknown_12("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_UNKNOWN_12: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ if (r_o.ptr_aliases != 0 && r_o.ptr_als_usrs != 0 &&
+ r_o.num_als_usrs1 == r_o.num_aliases1)
+ {
+ int i;
+
+ valid_query = True;
+ *num_aliases = r_o.num_aliases1;
+
+ for (i = 0; i < r_o.num_aliases1; i++)
+ {
+ fstrcpy(als_names[i], 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)
+ {
+ valid_query = True;
+ *num_aliases = 0;
+ }
+ else
+ {
+ p = False;
+ }
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_query;
+}
+
+/****************************************************************************
+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;
+ BOOL valid_query = False;
+
+ /* create and send a MSRPC command with api SAMR_QUERY_USERGROUPS */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Query User Groups.\n"));
+
+ if (pol == NULL || gid == NULL || num_groups == 0) return False;
+
+ /* store the parameters */
+ make_samr_q_query_usergroups(&q_o, pol);
+
+ /* turn parameters into data stream */
+ samr_io_q_query_usergroups("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_QUERY_USERGROUPS, &data, &rdata))
+ {
+ SAMR_R_QUERY_USERGROUPS r_o;
+ BOOL p;
+
+ /* get user info */
+ r_o.gid = gid;
+
+ samr_io_r_query_usergroups("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_USERGROUPS: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p && r_o.ptr_0 != 0)
+ {
+ valid_query = True;
+ *num_groups = r_o.num_entries;
+ }
+
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_query;
+}
+
+/****************************************************************************
+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;
+ BOOL valid_query = False;
+
+ /* create and send a MSRPC command with api SAMR_QUERY_USERINFO */
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ DEBUG(4,("SAMR Query User Info. level: %d\n", switch_value));
+
+ if (pol == NULL || usr == NULL || switch_value == 0) return False;
+
+ /* store the parameters */
+ make_samr_q_query_userinfo(&q_o, pol, switch_value);
+
+ /* turn parameters into data stream */
+ samr_io_q_query_userinfo("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_QUERY_USERINFO, &data, &rdata))
+ {
+ SAMR_R_QUERY_USERINFO r_o;
+ BOOL p;
+
+ /* get user info */
+ r_o.info.id = usr;
+
+ samr_io_r_query_userinfo("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_R_QUERY_USERINFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p && r_o.switch_value != switch_value)
+ {
+ DEBUG(0,("SAMR_R_QUERY_USERINFO: received incorrect level %d\n",
+ r_o.switch_value));
+ }
+
+ if (p && r_o.ptr != 0)
+ {
+ valid_query = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_query;
+}
+
+/****************************************************************************
+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;
+ BOOL valid_close = False;
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ if (hnd == NULL) return False;
+
+ /* create and send a MSRPC command with api SAMR_CLOSE_HND */
+
+ DEBUG(4,("SAMR Close\n"));
+
+ /* store the parameters */
+ make_samr_q_close_hnd(&q_c, hnd);
+
+ /* turn parameters into data stream */
+ samr_io_q_close_hnd("", &q_c, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, SAMR_CLOSE_HND, &data, &rdata))
+ {
+ SAMR_R_CLOSE_HND r_c;
+ BOOL p;
+
+ samr_io_r_close_hnd("", &r_c, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_c.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SAMR_CLOSE_HND: %s\n", get_nt_error_msg(r_c.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ /* check that the returned policy handle is all zeros */
+ int i;
+ valid_close = True;
+
+ for (i = 0; i < sizeof(r_c.pol.data); i++)
+ {
+ if (r_c.pol.data[i] != 0)
+ {
+ valid_close = False;
+ break;
+ }
+ }
+ if (!valid_close)
+ {
+ DEBUG(0,("SAMR_CLOSE_HND: non-zero handle returned\n"));
+ }
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_close;
+}
+
diff --git a/source/rpc_client/cli_srvsvc.c b/source/rpc_client/cli_srvsvc.c
new file mode 100644
index 00000000000..dcedeb3a546
--- /dev/null
+++ b/source/rpc_client/cli_srvsvc.c
@@ -0,0 +1,411 @@
+
+/*
+ * 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.
+ */
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+do a server net conn enum
+****************************************************************************/
+BOOL do_srv_net_srv_conn_enum(struct cli_state *cli, int t_idx, uint16 fnum,
+ 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;
+ BOOL valid_enum = False;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0) return False;
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_srv_q_net_conn_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ srv_io_q_net_conn_enum("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, t_idx, fnum, SRV_NETCONNENUM, &data, &rdata))
+ {
+ SRV_R_NET_CONN_ENUM r_o;
+ BOOL p;
+
+ r_o.ctr = ctr;
+
+ srv_io_r_net_conn_enum("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = 0;
+ }
+
+ if (p && 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));
+ p = 0;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ valid_enum = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_enum;
+}
+
+/****************************************************************************
+do a server net sess enum
+****************************************************************************/
+BOOL do_srv_net_srv_sess_enum(struct cli_state *cli, int t_idx, uint16 fnum,
+ 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;
+ BOOL valid_enum = False;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0) return False;
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_srv_q_net_sess_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ srv_io_q_net_sess_enum("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, t_idx, fnum, SRV_NETSESSENUM, &data, &rdata))
+ {
+ SRV_R_NET_SESS_ENUM r_o;
+ BOOL p;
+
+ r_o.ctr = ctr;
+
+ srv_io_r_net_sess_enum("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = 0;
+ }
+
+ if (p && 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));
+ p = 0;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ valid_enum = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_enum;
+}
+
+/****************************************************************************
+do a server net share enum
+****************************************************************************/
+BOOL do_srv_net_srv_share_enum(struct cli_state *cli, int t_idx, uint16 fnum,
+ char *server_name,
+ uint32 switch_value, SRV_SHARE_INFO_CTR *ctr,
+ uint32 preferred_len,
+ ENUM_HND *hnd)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SHARE_ENUM q_o;
+ BOOL valid_enum = False;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0) return False;
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ /* 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)));
+
+ q_o.share_level = switch_value;
+
+ ctr->switch_value = switch_value;
+ ctr->ptr_share_ctr = 1;
+ ctr->share.info1.num_entries_read = 0;
+ ctr->share.info1.ptr_share_info = 1;
+
+ /* store the parameters */
+ make_srv_q_net_share_enum(&q_o, server_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ srv_io_q_net_share_enum("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, t_idx, fnum, SRV_NETSHAREENUM, &data, &rdata))
+ {
+ SRV_R_NET_SHARE_ENUM r_o;
+ BOOL p;
+
+ r_o.ctr = ctr;
+
+ srv_io_r_net_share_enum("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = 0;
+ }
+
+ if (p && r_o.ctr->switch_value != switch_value)
+ {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_SHARE_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ p = 0;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ valid_enum = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_enum;
+}
+
+/****************************************************************************
+do a server net file enum
+****************************************************************************/
+BOOL do_srv_net_srv_file_enum(struct cli_state *cli, int t_idx, uint16 fnum,
+ 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;
+ BOOL valid_enum = False;
+
+ if (server_name == NULL || ctr == NULL || preferred_len == 0) return False;
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_srv_q_net_file_enum(&q_o, server_name, qual_name,
+ switch_value, ctr,
+ preferred_len,
+ hnd);
+
+ /* turn parameters into data stream */
+ srv_io_q_net_file_enum("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, t_idx, fnum, SRV_NETFILEENUM, &data, &rdata))
+ {
+ SRV_R_NET_FILE_ENUM r_o;
+ BOOL p;
+
+ r_o.ctr = ctr;
+
+ srv_io_r_net_file_enum("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = 0;
+ }
+
+ if (p && r_o.ctr->switch_value != switch_value)
+ {
+ /* different switch levels. oops. */
+ DEBUG(0,("SRV_R_NET_SRV_FILE_ENUM: info class %d does not match request %d\n",
+ r_o.ctr->switch_value, switch_value));
+ p = 0;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ valid_enum = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_enum;
+}
+
+/****************************************************************************
+do a server get info
+****************************************************************************/
+BOOL do_srv_net_srv_get_info(struct cli_state *cli, int t_idx, uint16 fnum,
+ char *server_name, uint32 switch_value, SRV_INFO_CTR *ctr)
+{
+ prs_struct data;
+ prs_struct rdata;
+ SRV_Q_NET_SRV_GET_INFO q_o;
+ BOOL valid_info = False;
+
+ if (server_name == NULL || switch_value == 0 || ctr == NULL) return False;
+
+ prs_init(&data , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rdata, 0 , 4, SAFETY_MARGIN, True );
+
+ /* 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 */
+ make_srv_q_net_srv_get_info(&q_o, server_name, switch_value);
+
+ /* turn parameters into data stream */
+ srv_io_q_net_srv_get_info("", &q_o, &data, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, t_idx, fnum, SRV_NET_SRV_GET_INFO, &data, &rdata))
+ {
+ SRV_R_NET_SRV_GET_INFO r_o;
+ BOOL p;
+
+ r_o.ctr = ctr;
+
+ srv_io_r_net_srv_get_info("", &r_o, &rdata, 0);
+ p = rdata.offset != 0;
+ p = rdata.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("SRV_R_NET_SRV_GET_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = 0;
+ }
+
+ if (p && 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));
+ p = 0;
+ }
+
+ if (p)
+ {
+ /* ok, at last: we're happy. */
+ valid_info = True;
+ }
+ }
+
+ prs_mem_free(&data );
+ prs_mem_free(&rdata );
+
+ return valid_info;
+}
+
diff --git a/source/rpc_client/cli_wkssvc.c b/source/rpc_client/cli_wkssvc.c
new file mode 100644
index 00000000000..a9640cdb423
--- /dev/null
+++ b/source/rpc_client/cli_wkssvc.c
@@ -0,0 +1,90 @@
+
+/*
+ * 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.
+ */
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+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;
+ BOOL valid_info = False;
+
+ if (server_name == 0 || wks100 == NULL) return False;
+
+ prs_init(&buf , 1024, 4, SAFETY_MARGIN, False);
+ prs_init(&rbuf, 0 , 4, SAFETY_MARGIN, True );
+
+ /* create and send a MSRPC command with api WKS_QUERY_INFO */
+
+ DEBUG(4,("WKS Query Info\n"));
+
+ /* store the parameters */
+ make_wks_q_query_info(&q_o, server_name, switch_value);
+
+ /* turn parameters into data stream */
+ wks_io_q_query_info("", &q_o, &buf, 0);
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, WKS_QUERY_INFO, &buf, &rbuf))
+ {
+ WKS_R_QUERY_INFO r_o;
+ BOOL p;
+
+ r_o.wks100 = wks100;
+
+ wks_io_r_query_info("", &r_o, &rbuf, 0);
+ p = rbuf.offset != 0;
+
+ if (p && r_o.status != 0)
+ {
+ /* report error code */
+ DEBUG(0,("WKS_R_QUERY_INFO: %s\n", get_nt_error_msg(r_o.status)));
+ p = False;
+ }
+
+ if (p)
+ {
+ valid_info = True;
+ }
+ }
+
+ prs_mem_free(&rbuf);
+ prs_mem_free(&buf );
+
+ return valid_info;
+}
+
diff --git a/source/rpc_client/ntclienttrust.c b/source/rpc_client/ntclienttrust.c
new file mode 100644
index 00000000000..04860171817
--- /dev/null
+++ b/source/rpc_client/ntclienttrust.c
@@ -0,0 +1,167 @@
+/*
+ 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.
+*/
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+
+/************************************************************************
+ check workstation trust account status
+ ************************************************************************/
+BOOL trust_account_check(struct in_addr dest_ip, char *dest_host,
+ char *myhostname, 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, myhostname);
+ 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, myhostname, dest_ip, dest_host))
+ {
+ cli_error(&cli_trust, &err_cls, &err_num);
+ 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);
+
+ 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..e69de29bb2d
--- /dev/null
+++ b/source/rpc_parse/.cvsignore
diff --git a/source/rpc_parse/parse_lsa.c b/source/rpc_parse/parse_lsa.c
new file mode 100644
index 00000000000..9db41b58b6e
--- /dev/null
+++ b/source/rpc_parse/parse_lsa.c
@@ -0,0 +1,571 @@
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+static void lsa_io_trans_names(char *desc, LSA_TRANS_NAME_ENUM *trn, prs_struct *ps, int depth);
+
+/*******************************************************************
+creates a LSA_TRANS_NAME structure.
+********************************************************************/
+void make_lsa_trans_name(LSA_TRANS_NAME *trn, uint32 sid_name_use, char *name, uint32 idx)
+{
+ int len_name = strlen(name);
+
+ trn->sid_name_use = sid_name_use;
+ make_uni_hdr(&(trn->hdr_name), len_name, len_name, len_name != 0);
+ make_unistr2(&(trn->uni_name), name, len_name);
+ trn->domain_idx = idx;
+}
+
+/*******************************************************************
+reads or writes a LSA_TRANS_NAME structure.
+********************************************************************/
+static void lsa_io_trans_name(char *desc, LSA_TRANS_NAME *trn, prs_struct *ps, int depth)
+{
+ if (trn == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_trans_name");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("sid_name_use", ps, depth, &(trn->sid_name_use));
+
+ smb_io_unihdr ("hdr_name", &(trn->hdr_name), ps, depth);
+ smb_io_unistr2("uni_name", &(trn->uni_name), trn->hdr_name.buffer, ps, depth);
+
+ prs_uint32("domain_idx ", ps, depth, &(trn->domain_idx ));
+}
+
+/*******************************************************************
+reads or writes a DOM_R_REF structure.
+********************************************************************/
+static void lsa_io_dom_r_ref(char *desc, DOM_R_REF *r_r, prs_struct *ps, int depth)
+{
+ int i;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_r_ref");
+ depth++;
+
+ if (r_r == NULL) return;
+
+ prs_align(ps);
+
+ prs_uint32("undoc_buffer ", ps, depth, &(r_r->undoc_buffer)); /* undocumented buffer pointer. */
+ prs_uint32("num_ref_doms_1 ", ps, depth, &(r_r->num_ref_doms_1)); /* num referenced domains? */
+ prs_uint32("buffer_dom_name", ps, depth, &(r_r->buffer_dom_name)); /* undocumented domain name buffer pointer. */
+ prs_uint32("max_entries ", ps, depth, &(r_r->max_entries)); /* 32 - max number of entries */
+ prs_uint32("num_ref_doms_2 ", ps, depth, &(r_r->num_ref_doms_2)); /* 4 - num referenced domains? */
+
+ smb_io_unihdr2("", &(r_r->hdr_dom_name), ps, depth); /* domain name unicode string header */
+
+ SMB_ASSERT_ARRAY(r_r->hdr_ref_dom, r_r->num_ref_doms_1-1);
+
+ for (i = 0; i < r_r->num_ref_doms_1-1; i++)
+ {
+ smb_io_unihdr2("", &(r_r->hdr_ref_dom[i]), ps, depth);
+ }
+
+ smb_io_unistr("", &(r_r->uni_dom_name), ps, depth); /* domain name unicode string */
+
+ SMB_ASSERT_ARRAY(r_r->ref_dom, r_r->num_ref_doms_2);
+
+ for (i = 0; i < r_r->num_ref_doms_2; i++)
+ {
+ smb_io_dom_sid2("", &(r_r->ref_dom[i]), ps, depth); /* referenced domain SIDs */
+ }
+}
+
+
+/*******************************************************************
+makes an LSA_OBJ_ATTR structure.
+********************************************************************/
+void make_lsa_obj_attr(LSA_OBJ_ATTR *attr, uint32 attributes, uint32 sec_qos)
+{
+ if (attr == NULL) return;
+
+ DEBUG(5,("make_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;
+ attr->sec_qos = sec_qos;
+}
+
+/*******************************************************************
+reads or writes an LSA_OBJ_ATTR structure.
+********************************************************************/
+static void lsa_io_obj_attr(char *desc, LSA_OBJ_ATTR *attr, prs_struct *ps, int depth)
+{
+ int start;
+
+ if (attr == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_obj_attr");
+ depth++;
+
+ prs_align(ps);
+
+ start = ps->offset;
+
+ /* these pointers had _better_ be zero, because we don't know
+ what they point to!
+ */
+ prs_uint32("len" , ps, depth, &(attr->len )); /* 0x18 - length (in bytes) inc. the length field. */
+ prs_uint32("ptr_root_dir", ps, depth, &(attr->ptr_root_dir)); /* 0 - root directory (pointer) */
+ prs_uint32("ptr_obj_name", ps, depth, &(attr->ptr_obj_name)); /* 0 - object name (pointer) */
+ prs_uint32("attributes" , ps, depth, &(attr->attributes )); /* 0 - attributes (undocumented) */
+ prs_uint32("ptr_sec_desc", ps, depth, &(attr->ptr_sec_desc)); /* 0 - security descriptior (pointer) */
+ prs_uint32("sec_qos" , ps, depth, &(attr->sec_qos )); /* 0 - security quality of service */
+
+ if (attr->len != ps->offset - start)
+ {
+ DEBUG(3,("lsa_io_obj_attr: length %x does not match size %x\n",
+ attr->len, ps->offset - start));
+ }
+}
+
+/*******************************************************************
+makes an LSA_Q_OPEN_POL structure.
+********************************************************************/
+void make_q_open_pol(LSA_Q_OPEN_POL *r_q, char *server_name,
+ uint32 attributes, uint32 sec_qos,
+ uint32 desired_access)
+{
+ if (r_q == NULL) return;
+
+ DEBUG(5,("make_open_pol\n"));
+
+ r_q->ptr = 1; /* undocumented pointer */
+
+ make_unistr2 (&(r_q->uni_server_name), server_name, strlen(server_name));
+ make_lsa_obj_attr(&(r_q->attr ), attributes, sec_qos);
+
+ r_q->des_access = desired_access;
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_OPEN_POL structure.
+********************************************************************/
+void lsa_io_q_open_pol(char *desc, LSA_Q_OPEN_POL *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_open_pol");
+ depth++;
+
+ prs_uint32("ptr ", ps, depth, &(r_q->ptr ));
+
+ smb_io_unistr2 ("", &(r_q->uni_server_name), r_q->ptr, ps, depth);
+ lsa_io_obj_attr("", &(r_q->attr ), ps, depth);
+
+ prs_uint32("des_access", ps, depth, &(r_q->des_access));
+}
+
+/*******************************************************************
+reads or writes an LSA_R_OPEN_POL structure.
+********************************************************************/
+void lsa_io_r_open_pol(char *desc, LSA_R_OPEN_POL *r_p, prs_struct *ps, int depth)
+{
+ if (r_p == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_open_pol");
+ depth++;
+
+
+ smb_io_pol_hnd("", &(r_p->pol), ps, depth);
+
+ prs_uint32("status", ps, depth, &(r_p->status));
+}
+
+/*******************************************************************
+makes an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+void make_q_query(LSA_Q_QUERY_INFO *q_q, POLICY_HND *hnd, uint16 info_class)
+{
+ if (q_q == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_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.
+********************************************************************/
+void lsa_io_q_query(char *desc, LSA_Q_QUERY_INFO *q_q, prs_struct *ps, int depth)
+{
+ if (q_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_query");
+ depth++;
+
+ smb_io_pol_hnd("", &(q_q->pol), ps, depth);
+
+ prs_uint16("info_class", ps, depth, &(q_q->info_class));
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_ENUM_TRUST_DOM structure.
+********************************************************************/
+void lsa_io_q_enum_trust_dom(char *desc, LSA_Q_ENUM_TRUST_DOM *q_e, prs_struct *ps, int depth)
+{
+ if (q_e == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_enum_trust_dom");
+ depth++;
+
+
+ smb_io_pol_hnd("", &(q_e->pol), ps, depth);
+
+ prs_uint32("enum_context ", ps, depth, &(q_e->enum_context ));
+ prs_uint32("preferred_len", ps, depth, &(q_e->preferred_len));
+}
+
+/*******************************************************************
+makes an LSA_R_ENUM_TRUST_DOM structure.
+********************************************************************/
+void make_r_enum_trust_dom(LSA_R_ENUM_TRUST_DOM *r_e,
+ uint32 enum_context, char *domain_name, DOM_SID *domain_sid,
+ uint32 status)
+{
+ if (r_e == NULL) return;
+
+ DEBUG(5,("make_r_enum_trust_dom\n"));
+
+ r_e->enum_context = enum_context;
+
+ if (status == 0)
+ {
+ int len_domain_name = strlen(domain_name);
+
+ r_e->num_domains = 1;
+ r_e->ptr_enum_domains = 1;
+ r_e->num_domains2 = 1;
+
+ make_uni_hdr2(&(r_e->hdr_domain_name ), len_domain_name, len_domain_name, 4);
+ make_unistr2 (&(r_e->uni_domain_name ), domain_name, len_domain_name);
+ make_dom_sid2(&(r_e->other_domain_sid), 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.
+********************************************************************/
+void lsa_io_r_enum_trust_dom(char *desc, LSA_R_ENUM_TRUST_DOM *r_e, prs_struct *ps, int depth)
+{
+ if (r_e == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_enum_trust_dom");
+ depth++;
+
+ prs_uint32("enum_context ", ps, depth, &(r_e->enum_context ));
+ prs_uint32("num_domains ", ps, depth, &(r_e->num_domains ));
+ prs_uint32("ptr_enum_domains", ps, depth, &(r_e->ptr_enum_domains));
+
+ if (r_e->ptr_enum_domains != 0)
+ {
+ prs_uint32("num_domains2", ps, depth, &(r_e->num_domains2));
+ smb_io_unihdr2 ("", &(r_e->hdr_domain_name ), ps, depth);
+ smb_io_unistr2 ("", &(r_e->uni_domain_name ), r_e->hdr_domain_name.buffer, ps, depth);
+ smb_io_dom_sid2("", &(r_e->other_domain_sid), ps, depth);
+ }
+
+ prs_uint32("status", ps, depth, &(r_e->status));
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_QUERY_INFO structure.
+********************************************************************/
+void lsa_io_r_query(char *desc, LSA_R_QUERY_INFO *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_query");
+ depth++;
+
+ prs_uint32("undoc_buffer", ps, depth, &(r_q->undoc_buffer));
+
+ if (r_q->undoc_buffer != 0)
+ {
+ prs_uint16("info_class", ps, depth, &(r_q->info_class));
+
+ switch (r_q->info_class)
+ {
+ case 3:
+ {
+ smb_io_dom_query_3("", &(r_q->dom.id3), ps, depth);
+ break;
+ }
+ case 5:
+ {
+ smb_io_dom_query_5("", &(r_q->dom.id3), ps, depth);
+ break;
+ }
+ default:
+ {
+ /* PANIC! */
+ break;
+ }
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_q->status));
+}
+
+/*******************************************************************
+reads or writes a LSA_SID_ENUM structure.
+********************************************************************/
+static void lsa_io_sid_enum(char *desc, LSA_SID_ENUM *sen, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (sen == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_sid_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries ", ps, depth, &(sen->num_entries));
+ prs_uint32("ptr_sid_enum", ps, depth, &(sen->ptr_sid_enum));
+ prs_uint32("num_entries2", ps, depth, &(sen->num_entries2));
+
+ SMB_ASSERT_ARRAY(sen->ptr_sid, sen->num_entries);
+
+ for (i = 0; i < sen->num_entries; i++)
+ {
+ fstring temp;
+ slprintf(temp, sizeof(temp) - 1, "ptr_sid[%d]", i);
+ prs_uint32(temp, ps, depth, &(sen->ptr_sid[i])); /* domain SID pointers to be looked up. */
+ }
+
+ SMB_ASSERT_ARRAY(sen->sid, sen->num_entries);
+
+ for (i = 0; i < sen->num_entries; i++)
+ {
+ fstring temp;
+ slprintf(temp, sizeof(temp) - 1, "sid[%d]", i);
+ smb_io_dom_sid2(temp, &(sen->sid[i]), ps, depth); /* domain SIDs to be looked up. */
+ }
+}
+
+/*******************************************************************
+reads or writes a LSA_Q_LOOKUP_SIDS structure.
+********************************************************************/
+void lsa_io_q_lookup_sids(char *desc, LSA_Q_LOOKUP_SIDS *q_s, prs_struct *ps, int depth)
+{
+ if (q_s == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_lookup_sids");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd ("pol_hnd", &(q_s->pol_hnd), ps, depth); /* policy handle */
+ lsa_io_sid_enum ("sids ", &(q_s->sids ), ps, depth); /* sids to be looked up */
+ lsa_io_trans_names ("names ", &(q_s->names ), ps, depth); /* translated names */
+ smb_io_lookup_level("switch ", &(q_s->level ), ps, depth); /* lookup level */
+
+ prs_uint32("mapped_count", ps, depth, &(q_s->mapped_count));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void lsa_io_trans_names(char *desc, LSA_TRANS_NAME_ENUM *trn, prs_struct *ps, int depth)
+{
+ int i;
+ int i2;
+
+ if (trn == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_trans_names");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries ", ps, depth, &(trn->num_entries));
+ prs_uint32("ptr_trans_names", ps, depth, &(trn->ptr_trans_names));
+ prs_uint32("num_entries2 ", ps, depth, &(trn->num_entries2));
+
+ SMB_ASSERT_ARRAY(trn->ptr_name, trn->num_entries);
+
+ for (i = 0; i < trn->num_entries; i++)
+ {
+ fstring temp;
+ slprintf(temp, sizeof(temp) - 1, "ptr_name[%d] ", i);
+ prs_uint32(temp, ps, depth, &(trn->ptr_name[i])); /* pointer to translated name */
+ }
+
+ for (i = 0, i2 = 0; i < trn->num_entries2; i++)
+ {
+ if (trn->ptr_name[i] != 0)
+ {
+ fstring temp;
+ slprintf(temp, sizeof(temp) - 1, "name[%d] ", i);
+ lsa_io_trans_name(temp, &(trn->name[i2]), ps, depth); /* translated name */
+ i2++;
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void lsa_io_r_lookup_sids(char *desc, LSA_R_LOOKUP_SIDS *r_s, prs_struct *ps, int depth)
+{
+ if (r_s == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_lookup_sids");
+ depth++;
+
+ prs_align(ps);
+
+ lsa_io_dom_r_ref ("dom_ref", r_s->dom_ref, ps, depth); /* domain reference info */
+ lsa_io_trans_names("names ", r_s->names , ps, depth); /* translated names */
+
+ prs_uint32("mapped_count", ps, depth, &(r_s->mapped_count));
+
+ prs_uint32("status ", ps, depth, &(r_s->status));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void lsa_io_q_lookup_rids(char *desc, LSA_Q_LOOKUP_RIDS *q_r, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (q_r == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_lookup_rids");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(q_r->pol_hnd), ps, depth); /* policy handle */
+
+ prs_uint32("num_entries ", ps, depth, &(q_r->num_entries));
+ prs_uint32("num_entries2 ", ps, depth, &(q_r->num_entries2));
+ prs_uint32("buffer_dom_sid ", ps, depth, &(q_r->buffer_dom_sid)); /* undocumented domain SID buffer pointer */
+ prs_uint32("buffer_dom_name", ps, depth, &(q_r->buffer_dom_name)); /* undocumented domain name buffer pointer */
+
+ SMB_ASSERT_ARRAY(q_r->lookup_name, q_r->num_entries);
+
+ for (i = 0; i < q_r->num_entries; i++)
+ {
+ smb_io_dom_name("", &(q_r->lookup_name[i]), ps, depth); /* names to be looked up */
+ }
+
+ prs_uint8s (False, "undoc ", ps, depth, q_r->undoc, UNKNOWN_LEN);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void lsa_io_r_lookup_rids(char *desc, LSA_R_LOOKUP_RIDS *r_r, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (r_r == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_lookup_rids");
+ depth++;
+
+ prs_align(ps);
+
+ lsa_io_dom_r_ref("", &(r_r->dom_ref), ps, depth); /* domain reference info */
+
+ prs_uint32("num_entries ", ps, depth, &(r_r->num_entries));
+ prs_uint32("undoc_buffer", ps, depth, &(r_r->undoc_buffer));
+ prs_uint32("num_entries2", ps, depth, &(r_r->num_entries2));
+
+ SMB_ASSERT_ARRAY(r_r->dom_rid, r_r->num_entries2);
+
+ for (i = 0; i < r_r->num_entries2; i++)
+ {
+ smb_io_dom_rid2("", &(r_r->dom_rid[i]), ps, depth); /* domain RIDs being looked up */
+ }
+
+ prs_uint32("num_entries3", ps, depth, &(r_r->num_entries3));
+
+ prs_uint32("status ", ps, depth, &(r_r->status));
+}
+
+
+/*******************************************************************
+makes an LSA_Q_CLOSE structure.
+********************************************************************/
+void make_lsa_q_close(LSA_Q_CLOSE *q_c, POLICY_HND *hnd)
+{
+ if (q_c == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_lsa_q_close\n"));
+
+ memcpy(&(q_c->pol), hnd, sizeof(q_c->pol));
+}
+
+/*******************************************************************
+reads or writes an LSA_Q_CLOSE structure.
+********************************************************************/
+void lsa_io_q_close(char *desc, LSA_Q_CLOSE *q_c, prs_struct *ps, int depth)
+{
+ if (q_c == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_q_close");
+ depth++;
+
+ smb_io_pol_hnd("", &(q_c->pol), ps, depth);
+}
+
+/*******************************************************************
+reads or writes an LSA_R_CLOSE structure.
+********************************************************************/
+void lsa_io_r_close(char *desc, LSA_R_CLOSE *r_c, prs_struct *ps, int depth)
+{
+ if (r_c == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_r_close");
+ depth++;
+
+ smb_io_pol_hnd("", &(r_c->pol), ps, depth);
+
+ prs_uint32("status", ps, depth, &(r_c->status));
+}
+
diff --git a/source/rpc_parse/parse_misc.c b/source/rpc_parse/parse_misc.c
new file mode 100644
index 00000000000..5144ef8c311
--- /dev/null
+++ b/source/rpc_parse/parse_misc.c
@@ -0,0 +1,966 @@
+
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+
+
+/*******************************************************************
+reads or writes a UTIME type.
+********************************************************************/
+static void smb_io_utime(char *desc, UTIME *t, prs_struct *ps, int depth)
+{
+ if (t == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_utime");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32 ("time", ps, depth, &(t->time));
+}
+
+/*******************************************************************
+reads or writes an NTTIME structure.
+********************************************************************/
+void smb_io_time(char *desc, NTTIME *nttime, prs_struct *ps, int depth)
+{
+ if (nttime == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_time");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("low ", ps, depth, &(nttime->low )); /* low part */
+ prs_uint32("high", ps, depth, &(nttime->high)); /* high part */
+}
+
+/*******************************************************************
+reads or writes a LOOKUP_LEVEL structure.
+********************************************************************/
+void smb_io_lookup_level(char *desc, LOOKUP_LEVEL *level, prs_struct *ps, int depth)
+{
+ if (level == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_lookup_level");
+ depth++;
+
+ prs_align(ps);
+ prs_uint16("value", ps, depth, &(level->value));
+ prs_align(ps);
+}
+
+/*******************************************************************
+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;
+}
+
+/*******************************************************************
+makes an ENUM_HND structure.
+********************************************************************/
+void make_enum_hnd(ENUM_HND *enh, uint32 hnd)
+{
+ if (enh == NULL) return;
+
+ DEBUG(5,("smb_io_enum_hnd\n"));
+
+ enh->ptr_hnd = (hnd != 0) ? 1 : 0;
+ enh->handle = hnd;
+}
+
+/*******************************************************************
+reads or writes an ENUM_HND structure.
+********************************************************************/
+void smb_io_enum_hnd(char *desc, ENUM_HND *hnd, prs_struct *ps, int depth)
+{
+ if (hnd == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_enum_hnd");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_hnd", ps, depth, &(hnd->ptr_hnd)); /* pointer */
+ if (hnd->ptr_hnd != 0)
+ {
+ prs_uint32("handle ", ps, depth, &(hnd->handle )); /* enum handle */
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_SID structure.
+********************************************************************/
+void smb_io_dom_sid(char *desc, DOM_SID *sid, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (sid == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_sid");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint8 ("sid_rev_num", ps, depth, &(sid->sid_rev_num));
+ prs_uint8 ("num_auths ", ps, depth, &(sid->num_auths));
+
+ for (i = 0; i < 6; i++)
+ {
+ fstring tmp;
+ slprintf(tmp, sizeof(tmp) - 1, "id_auth[%d] ", i);
+ prs_uint8 (tmp, ps, depth, &(sid->id_auth[i]));
+ }
+
+ /* oops! XXXX should really issue a warning here... */
+ if (sid->num_auths > MAXSUBAUTHS) sid->num_auths = MAXSUBAUTHS;
+
+ prs_uint32s(False, "sub_auths ", ps, depth, sid->sub_auths, sid->num_auths);
+}
+
+/*******************************************************************
+creates 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 make_dom_sid(DOM_SID *sid, char *str_sid)
+{
+ pstring domsid;
+ int identauth;
+ char *p;
+
+ if (sid == NULL) return;
+
+ if (domsid == NULL)
+ {
+ DEBUG(4,("netlogon domain SID: none\n"));
+ sid->sid_rev_num = 0;
+ sid->num_auths = 0;
+ return;
+ }
+
+ pstrcpy(domsid, str_sid);
+
+ DEBUG(4,("make_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,("make_dom_sid: %d SID: %s\n", __LINE__, domsid));
+}
+/*******************************************************************
+creates a DOM_SID2 structure.
+********************************************************************/
+void make_dom_sid2(DOM_SID2 *sid2, DOM_SID *sid)
+{
+ sid2->sid = *sid;
+ sid2->num_auths = sid2->sid.num_auths;
+}
+
+/*******************************************************************
+reads or writes a DOM_SID2 structure.
+********************************************************************/
+void smb_io_dom_sid2(char *desc, DOM_SID2 *sid, prs_struct *ps, int depth)
+{
+ if (sid == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_sid2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_auths", ps, depth, &(sid->num_auths));
+
+ smb_io_dom_sid("sid", &(sid->sid), ps, depth);
+}
+
+/*******************************************************************
+creates a STRHDR structure.
+********************************************************************/
+void make_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.
+********************************************************************/
+void smb_io_strhdr(char *desc, STRHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_strhdr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint16("str_str_len", ps, depth, &(hdr->str_str_len));
+ prs_uint16("str_max_len", ps, depth, &(hdr->str_max_len));
+ prs_uint32("buffer ", ps, depth, &(hdr->buffer ));
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (hdr->str_max_len > MAX_STRINGLEN) hdr->str_max_len = MAX_STRINGLEN;
+ if (hdr->str_str_len > MAX_STRINGLEN) hdr->str_str_len = MAX_STRINGLEN;
+}
+
+/*******************************************************************
+creates a UNIHDR structure.
+********************************************************************/
+void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint32 buffer)
+{
+ hdr->uni_max_len = 2 * max_len;
+ hdr->uni_str_len = 2 * len;
+ hdr->buffer = buffer;
+}
+
+/*******************************************************************
+reads or writes a UNIHDR structure.
+********************************************************************/
+void smb_io_unihdr(char *desc, UNIHDR *hdr, prs_struct *ps, int depth)
+{
+ if (hdr == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_unihdr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint16("uni_str_len", ps, depth, &(hdr->uni_str_len));
+ prs_uint16("uni_max_len", ps, depth, &(hdr->uni_max_len));
+ prs_uint32("buffer ", ps, depth, &(hdr->buffer ));
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (hdr->uni_max_len > MAX_UNISTRLEN) hdr->uni_max_len = MAX_UNISTRLEN;
+ if (hdr->uni_str_len > MAX_UNISTRLEN) hdr->uni_str_len = MAX_UNISTRLEN;
+}
+
+/*******************************************************************
+creates a UNIHDR2 structure.
+********************************************************************/
+void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate)
+{
+ make_uni_hdr(&(hdr->unihdr), max_len, len, terminate);
+ hdr->buffer = len > 0 ? 1 : 0;
+}
+
+/*******************************************************************
+reads or writes a UNIHDR2 structure.
+********************************************************************/
+void smb_io_unihdr2(char *desc, UNIHDR2 *hdr2, prs_struct *ps, int depth)
+{
+ if (hdr2 == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_unihdr2");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unihdr("hdr", &(hdr2->unihdr), ps, depth);
+ prs_uint32("buffer", ps, depth, &(hdr2->buffer));
+}
+
+/*******************************************************************
+creates a UNISTR structure.
+********************************************************************/
+void make_unistr(UNISTR *str, char *buf)
+{
+ /* store the string (null-terminated copy) */
+ struni2(str->buffer, buf);
+}
+
+/*******************************************************************
+reads or writes a UNISTR structure.
+XXXX NOTE: UNISTR structures NEED to be null-terminated.
+********************************************************************/
+void smb_io_unistr(char *desc, UNISTR *uni, prs_struct *ps, int depth)
+{
+ if (uni == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_unistr");
+ depth++;
+
+ prs_align(ps);
+ prs_unistr("unistr", ps, depth, uni);
+}
+
+/*******************************************************************
+creates a UNINOTSTR2 structure.
+********************************************************************/
+void make_uninotstr2(UNINOTSTR2 *str, char *buf, int len)
+{
+ /* set up string lengths. add one if string is not null-terminated */
+ str->uni_max_len = (len+1)*2;
+ str->undoc = 0;
+ str->uni_buf_len = (len+1)*2;
+
+ /* store the string (null-terminated copy) */
+ struni2(str->buffer, buf);
+}
+
+/*******************************************************************
+reads or writes a UNINOTSTR2 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.
+********************************************************************/
+void smb_io_uninotstr2(char *desc, UNINOTSTR2 *uni2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (uni2 == NULL) return;
+
+ if (buffer)
+ {
+ prs_debug(ps, depth, desc, "smb_io_uninotstr2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("uni_max_len", ps, depth, &(uni2->uni_max_len));
+ prs_uint32("undoc ", ps, depth, &(uni2->undoc ));
+ prs_uint32("uni_buf_len", ps, depth, &(uni2->uni_buf_len));
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (uni2->uni_max_len > MAX_UNISTRLEN) uni2->uni_max_len = MAX_UNISTRLEN;
+ if (uni2->uni_buf_len > MAX_UNISTRLEN) uni2->uni_buf_len = MAX_UNISTRLEN;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ prs_uninotstr2(True, "buffer ", ps, depth, uni2);
+ }
+ else
+ {
+ prs_debug(ps, depth, desc, "smb_io_uninotstr2 - NULL");
+ depth++;
+ bzero(uni2, sizeof(*uni2));
+ }
+}
+
+/*******************************************************************
+creates a UNISTR2 structure: sets up the buffer, too
+********************************************************************/
+void make_buf_unistr2(UNISTR2 *str, uint32 *ptr, char *buf)
+{
+ if (buf != NULL)
+ {
+ *ptr = 1;
+ make_unistr2(str, buf, strlen(buf));
+ }
+ else
+ {
+ *ptr = 0;
+ make_unistr2(str, "", 0);
+ }
+}
+
+/*******************************************************************
+copies a UNISTR2 structure.
+********************************************************************/
+void copy_unistr2(UNISTR2 *str, 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;
+
+ /* copy the string */
+ memcpy(str->buffer, from->buffer, sizeof(from->buffer));
+}
+
+/*******************************************************************
+creates a STRING2 structure.
+********************************************************************/
+void make_string2(STRING2 *str, char *buf, int len)
+{
+ /* set up string lengths. */
+ str->str_max_len = len;
+ str->undoc = 0;
+ str->str_str_len = len;
+
+ /* store the string */
+ if(len != 0)
+ memcpy(str->buffer, buf, 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.
+********************************************************************/
+void smb_io_string2(char *desc, STRING2 *str2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (str2 == NULL) return;
+
+ if (buffer)
+ {
+ prs_debug(ps, depth, desc, "smb_io_string2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("str_max_len", ps, depth, &(str2->str_max_len));
+ prs_uint32("undoc ", ps, depth, &(str2->undoc ));
+ prs_uint32("str_str_len", ps, depth, &(str2->str_str_len));
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (str2->str_max_len > MAX_STRINGLEN) str2->str_max_len = MAX_STRINGLEN;
+ if (str2->str_str_len > MAX_STRINGLEN) str2->str_str_len = MAX_STRINGLEN;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ prs_string2(True, "buffer ", ps, depth, str2);
+ }
+ else
+ {
+ prs_debug(ps, depth, desc, "smb_io_string2 - NULL");
+ depth++;
+ bzero(str2, sizeof(*str2));
+ }
+}
+
+/*******************************************************************
+creates a UNISTR2 structure.
+********************************************************************/
+void make_unistr2(UNISTR2 *str, char *buf, int len)
+{
+ /* set up string lengths. add one if string is not null-terminated */
+ str->uni_max_len = len+1;
+ str->undoc = 0;
+ str->uni_str_len = len+1;
+
+ /* store the string (null-terminated 8 bit chars into 16 bit chars) */
+ struni2(str->buffer, buf);
+}
+
+/*******************************************************************
+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.
+********************************************************************/
+void smb_io_unistr2(char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth)
+{
+ if (uni2 == NULL) return;
+
+ if (buffer)
+ {
+ prs_debug(ps, depth, desc, "smb_io_unistr2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("uni_max_len", ps, depth, &(uni2->uni_max_len));
+ prs_uint32("undoc ", ps, depth, &(uni2->undoc ));
+ prs_uint32("uni_str_len", ps, depth, &(uni2->uni_str_len));
+
+ /* oops! XXXX maybe issue a warning that this is happening... */
+ if (uni2->uni_max_len > MAX_UNISTRLEN) uni2->uni_max_len = MAX_UNISTRLEN;
+ if (uni2->uni_str_len > MAX_UNISTRLEN) uni2->uni_str_len = MAX_UNISTRLEN;
+
+ /* buffer advanced by indicated length of string
+ NOT by searching for null-termination */
+ prs_unistr2(True, "buffer ", ps, depth, uni2);
+ }
+ else
+ {
+ prs_debug(ps, depth, desc, "smb_io_unistr2 - NULL");
+ depth++;
+ bzero(uni2, sizeof(*uni2));
+ }
+}
+
+/*******************************************************************
+creates a DOM_RID2 structure.
+********************************************************************/
+void make_dom_rid2(DOM_RID2 *rid2, uint32 rid)
+{
+ rid2->type = 0x5;
+ rid2->undoc = 0x5;
+ rid2->rid = rid;
+ rid2->rid_idx = 0;
+}
+
+/*******************************************************************
+reads or writes a DOM_RID2 structure.
+********************************************************************/
+void smb_io_dom_rid2(char *desc, DOM_RID2 *rid2, prs_struct *ps, int depth)
+{
+ if (rid2 == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid2");
+ depth++;
+
+ prs_align(ps);
+
+ /* should be value 5, so enforce it */
+ rid2->type = 5;
+
+ /* should be value 5, so enforce it */
+ rid2->undoc = 5;
+
+ prs_uint32("type ", ps, depth, &(rid2->type));
+ prs_uint32("undoc ", ps, depth, &(rid2->undoc ));
+ prs_uint32("rid ", ps, depth, &(rid2->rid ));
+ prs_uint32("rid_idx", ps, depth, &(rid2->rid_idx ));
+}
+
+/*******************************************************************
+creates a DOM_RID3 structure.
+********************************************************************/
+void make_dom_rid3(DOM_RID3 *rid3, uint32 rid)
+{
+ rid3->rid = rid;
+ rid3->type1 = 0x1;
+ rid3->ptr_type = 0x1; /* non-zero, basically. */
+ rid3->type2 = 0x1;
+}
+
+/*******************************************************************
+reads or writes a DOM_RID3 structure.
+********************************************************************/
+void smb_io_dom_rid3(char *desc, DOM_RID3 *rid3, prs_struct *ps, int depth)
+{
+ if (rid3 == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_rid3");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("rid ", ps, depth, &(rid3->rid ));
+ prs_uint32("type1 ", ps, depth, &(rid3->type1 ));
+ prs_uint32("ptr_type", ps, depth, &(rid3->ptr_type));
+ prs_uint32("type2 ", ps, depth, &(rid3->type2 ));
+}
+
+/*******************************************************************
+creates a DOM_RID4 structure.
+********************************************************************/
+void make_dom_rid4(DOM_RID4 *rid4, uint16 unknown, uint16 attr, uint32 rid)
+{
+ rid4->unknown = unknown;
+ rid4->attr = attr;
+ rid4->rid = rid;
+}
+
+
+/*******************************************************************
+makes a DOM_CLNT_SRV structure.
+********************************************************************/
+static void make_clnt_srv(DOM_CLNT_SRV *log, char *logon_srv, char *comp_name)
+{
+ if (log == NULL) return;
+
+ DEBUG(5,("make_clnt_srv: %d\n", __LINE__));
+
+ if (logon_srv != NULL)
+ {
+ log->undoc_buffer = 1;
+ make_unistr2(&(log->uni_logon_srv), logon_srv, strlen(logon_srv));
+ }
+ else
+ {
+ log->undoc_buffer = 0;
+ }
+
+ if (comp_name != NULL)
+ {
+ log->undoc_buffer2 = 1;
+ make_unistr2(&(log->uni_comp_name), comp_name, strlen(comp_name));
+ }
+ else
+ {
+ log->undoc_buffer2 = 0;
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_CLNT_SRV structure.
+********************************************************************/
+static void smb_io_clnt_srv(char *desc, DOM_CLNT_SRV *log, prs_struct *ps, int depth)
+{
+ if (log == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_srv");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("undoc_buffer ", ps, depth, &(log->undoc_buffer ));
+ if (log->undoc_buffer != 0)
+ {
+ smb_io_unistr2("unistr2", &(log->uni_logon_srv), log->undoc_buffer, ps, depth);
+ }
+
+ prs_align(ps);
+
+ prs_uint32("undoc_buffer2", ps, depth, &(log->undoc_buffer2));
+ if (log->undoc_buffer2 != 0)
+ {
+ smb_io_unistr2("unistr2", &(log->uni_comp_name), log->undoc_buffer2, ps, depth);
+ }
+}
+
+/*******************************************************************
+makes a DOM_LOG_INFO structure.
+********************************************************************/
+void make_log_info(DOM_LOG_INFO *log, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name)
+{
+ if (log == NULL) return;
+
+ DEBUG(5,("make_log_info %d\n", __LINE__));
+
+ log->undoc_buffer = 1;
+
+ make_unistr2(&(log->uni_logon_srv), logon_srv, strlen(logon_srv));
+ make_unistr2(&(log->uni_acct_name), acct_name, strlen(acct_name));
+
+ log->sec_chan = sec_chan;
+
+ make_unistr2(&(log->uni_comp_name), comp_name, strlen(comp_name));
+}
+
+/*******************************************************************
+reads or writes a DOM_LOG_INFO structure.
+********************************************************************/
+void smb_io_log_info(char *desc, DOM_LOG_INFO *log, prs_struct *ps, int depth)
+{
+ if (log == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_log_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("undoc_buffer", ps, depth, &(log->undoc_buffer));
+
+ smb_io_unistr2("unistr2", &(log->uni_logon_srv), True, ps, depth);
+ smb_io_unistr2("unistr2", &(log->uni_acct_name), True, ps, depth);
+
+ prs_uint16("sec_chan", ps, depth, &(log->sec_chan));
+
+ smb_io_unistr2("unistr2", &(log->uni_comp_name), True, ps, depth);
+}
+
+/*******************************************************************
+reads or writes a DOM_CHAL structure.
+********************************************************************/
+void smb_io_chal(char *desc, DOM_CHAL *chal, prs_struct *ps, int depth)
+{
+ if (chal == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_chal");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint8s (False, "data", ps, depth, chal->data, 8);
+}
+
+/*******************************************************************
+reads or writes a DOM_CRED structure.
+********************************************************************/
+void smb_io_cred(char *desc, DOM_CRED *cred, prs_struct *ps, int depth)
+{
+ if (cred == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_cred");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_chal ("", &(cred->challenge), ps, depth);
+ smb_io_utime("", &(cred->timestamp), ps, depth);
+}
+
+/*******************************************************************
+makes a DOM_CLNT_INFO2 structure.
+********************************************************************/
+void make_clnt_info2(DOM_CLNT_INFO2 *clnt,
+ char *logon_srv, char *comp_name,
+ DOM_CRED *clnt_cred)
+{
+ if (clnt == NULL) return;
+
+ DEBUG(5,("make_clnt_info: %d\n", __LINE__));
+
+ make_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.
+********************************************************************/
+void smb_io_clnt_info2(char *desc, DOM_CLNT_INFO2 *clnt, prs_struct *ps, int depth)
+{
+ if (clnt == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_info2");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_clnt_srv("", &(clnt->login), ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("ptr_cred", ps, depth, &(clnt->ptr_cred));
+ smb_io_cred ("", &(clnt->cred ), ps, depth);
+}
+
+/*******************************************************************
+makes a DOM_CLNT_INFO structure.
+********************************************************************/
+void make_clnt_info(DOM_CLNT_INFO *clnt,
+ char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name,
+ DOM_CRED *cred)
+{
+ if (clnt == NULL || cred == NULL) return;
+
+ DEBUG(5,("make_clnt_info\n"));
+
+ make_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.
+********************************************************************/
+void smb_io_clnt_info(char *desc, DOM_CLNT_INFO *clnt, prs_struct *ps, int depth)
+{
+ if (clnt == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_clnt_info");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_log_info("", &(clnt->login), ps, depth);
+ smb_io_cred ("", &(clnt->cred ), ps, depth);
+}
+
+/*******************************************************************
+makes a DOM_LOGON_ID structure.
+********************************************************************/
+void make_logon_id(DOM_LOGON_ID *log, uint32 log_id_low, uint32 log_id_high)
+{
+ if (log == NULL) return;
+
+ 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.
+********************************************************************/
+void smb_io_logon_id(char *desc, DOM_LOGON_ID *log, prs_struct *ps, int depth)
+{
+ if (log == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_logon_id");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("low ", ps, depth, &(log->low ));
+ prs_uint32("high", ps, depth, &(log->high));
+}
+
+/*******************************************************************
+makes an OWF_INFO structure.
+********************************************************************/
+void make_owf_info(OWF_INFO *hash, uint8 data[16])
+{
+ if (hash == NULL) return;
+
+ DEBUG(5,("make_owf_info: %d\n", __LINE__));
+
+ if (data != NULL)
+ {
+ memcpy(hash->data, data, sizeof(hash->data));
+ }
+ else
+ {
+ bzero(hash->data, sizeof(hash->data));
+ }
+}
+
+/*******************************************************************
+reads or writes an OWF_INFO structure.
+********************************************************************/
+void smb_io_owf_info(char *desc, OWF_INFO *hash, prs_struct *ps, int depth)
+{
+ if (hash == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_owf_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint8s (False, "data", ps, depth, hash->data, 16);
+}
+
+/*******************************************************************
+reads or writes a DOM_GID structure.
+********************************************************************/
+void smb_io_gid(char *desc, DOM_GID *gid, prs_struct *ps, int depth)
+{
+ if (gid == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_gid");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("g_rid", ps, depth, &(gid->g_rid));
+ prs_uint32("attr ", ps, depth, &(gid->attr ));
+}
+
+/*******************************************************************
+reads or writes an POLICY_HND structure.
+********************************************************************/
+void smb_io_pol_hnd(char *desc, POLICY_HND *pol, prs_struct *ps, int depth)
+{
+ if (pol == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_pol_hnd");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint8s (False, "data", ps, depth, pol->data, POL_HND_SIZE);
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+static void smb_io_dom_query(char *desc, DOM_QUERY *d_q, prs_struct *ps, int depth)
+{
+ if (d_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_query");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint16("uni_dom_max_len", ps, depth, &(d_q->uni_dom_max_len)); /* domain name string length * 2 */
+ prs_uint16("uni_dom_str_len", ps, depth, &(d_q->uni_dom_str_len)); /* domain name string length * 2 */
+
+ prs_uint32("buffer_dom_name", ps, depth, &(d_q->buffer_dom_name)); /* undocumented domain name string buffer pointer */
+ prs_uint32("buffer_dom_sid ", ps, depth, &(d_q->buffer_dom_sid )); /* undocumented domain SID string buffer pointer */
+
+ smb_io_unistr2("unistr2", &(d_q->uni_domain_name), d_q->buffer_dom_name, ps, depth); /* domain name (unicode string) */
+
+ if (d_q->buffer_dom_sid != 0)
+ {
+ smb_io_dom_sid2("", &(d_q->dom_sid), ps, depth); /* domain SID */
+ }
+ else
+ {
+ bzero(&(d_q->dom_sid), sizeof(d_q->dom_sid));
+ }
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+void smb_io_dom_query_3(char *desc, DOM_QUERY_3 *d_q, prs_struct *ps, int depth)
+{
+ smb_io_dom_query("", d_q, ps, depth);
+}
+
+/*******************************************************************
+reads or writes a dom query structure.
+********************************************************************/
+void smb_io_dom_query_5(char *desc, DOM_QUERY_3 *d_q, prs_struct *ps, int depth)
+{
+ smb_io_dom_query("", d_q, ps, depth);
+}
+
+
+/*******************************************************************
+reads or writes a DOM_NAME structure.
+********************************************************************/
+void smb_io_dom_name(char *desc, DOM_NAME *name, prs_struct *ps, int depth)
+{
+ if (name == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_dom_name");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("uni_str_len", ps, depth, &(name->uni_str_len));
+
+ /* don't know if len is specified by uni_str_len member... */
+ /* assume unicode string is unicode-null-terminated, instead */
+
+ smb_io_unistr("", &(name->str), ps, depth);
+}
+
+
diff --git a/source/rpc_parse/parse_net.c b/source/rpc_parse/parse_net.c
new file mode 100644
index 00000000000..12d6aca264f
--- /dev/null
+++ b/source/rpc_parse/parse_net.c
@@ -0,0 +1,1050 @@
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void net_io_neg_flags(char *desc, NEG_FLAGS *neg, prs_struct *ps, int depth)
+{
+ if (neg == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_neg_flags");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("neg_flags", ps, depth, &(neg->neg_flags));
+}
+
+/*******************************************************************
+creates a NETLOGON_INFO_3 structure.
+********************************************************************/
+static void make_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 void net_io_netinfo_3(char *desc, NETLOGON_INFO_3 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_netinfo_3");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("flags ", ps, depth, &(info->flags ));
+ prs_uint32("logon_attempts", ps, depth, &(info->logon_attempts));
+ prs_uint32("reserved_1 ", ps, depth, &(info->reserved_1 ));
+ prs_uint32("reserved_2 ", ps, depth, &(info->reserved_2 ));
+ prs_uint32("reserved_3 ", ps, depth, &(info->reserved_3 ));
+ prs_uint32("reserved_4 ", ps, depth, &(info->reserved_4 ));
+ prs_uint32("reserved_5 ", ps, depth, &(info->reserved_5 ));
+}
+
+
+/*******************************************************************
+creates a NETLOGON_INFO_1 structure.
+********************************************************************/
+static void make_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 void net_io_netinfo_1(char *desc, NETLOGON_INFO_1 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_netinfo_1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("flags ", ps, depth, &(info->flags ));
+ prs_uint32("pdc_status", ps, depth, &(info->pdc_status));
+}
+
+/*******************************************************************
+creates a NETLOGON_INFO_2 structure.
+********************************************************************/
+static void make_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)
+ {
+ make_unistr2(&(info->uni_trusted_dc_name), trusted_dc_name, len_dc_name);
+ }
+ else
+ {
+ make_unistr2(&(info->uni_trusted_dc_name), "", 1);
+ }
+}
+
+/*******************************************************************
+reads or writes a NETLOGON_INFO_2 structure.
+********************************************************************/
+static void net_io_netinfo_2(char *desc, NETLOGON_INFO_2 *info, prs_struct *ps, int depth)
+{
+ if (info == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_netinfo_2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("flags ", ps, depth, &(info->flags ));
+ prs_uint32("pdc_status ", ps, depth, &(info->pdc_status ));
+ prs_uint32("ptr_trusted_dc_name", ps, depth, &(info->ptr_trusted_dc_name));
+ prs_uint32("tc_status ", ps, depth, &(info->tc_status ));
+
+ if (info->ptr_trusted_dc_name != 0)
+ {
+ smb_io_unistr2("unistr2", &(info->uni_trusted_dc_name), info->ptr_trusted_dc_name, ps, depth);
+ }
+
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes an NET_Q_LOGON_CTRL2 structure.
+********************************************************************/
+void net_io_q_logon_ctrl2(char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_q_logon_ctrl2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr ", ps, depth, &(q_l->ptr ));
+
+ smb_io_unistr2 ("", &(q_l->uni_server_name), q_l->ptr, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("function_code", ps, depth, &(q_l->function_code));
+ prs_uint32("query_level ", ps, depth, &(q_l->query_level ));
+ prs_uint32("switch_value ", ps, depth, &(q_l->switch_value ));
+}
+
+/*******************************************************************
+makes an NET_R_LOGON_CTRL2 structure.
+********************************************************************/
+void make_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)
+{
+ if (r_l == NULL) return;
+
+ DEBUG(5,("make_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 */
+ make_netinfo_1(&(r_l->logon.info1), flags, pdc_status);
+ r_l->status = 0;
+
+ break;
+ }
+ case 2:
+ {
+ r_l->ptr = 1; /* undocumented pointer */
+ make_netinfo_2(&(r_l->logon.info2), flags, pdc_status,
+ tc_status, trusted_domain_name);
+ r_l->status = 0;
+
+ break;
+ }
+ case 3:
+ {
+ r_l->ptr = 1; /* undocumented pointer */
+ make_netinfo_3(&(r_l->logon.info3), flags, logon_attempts);
+ r_l->status = 0;
+
+ break;
+ }
+ default:
+ {
+ DEBUG(2,("make_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.
+********************************************************************/
+void net_io_r_logon_ctrl2(char *desc, NET_R_LOGON_CTRL2 *r_l, prs_struct *ps, int depth)
+{
+ if (r_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_logon_ctrl2");
+ depth++;
+
+ prs_uint32("switch_value ", ps, depth, &(r_l->switch_value ));
+ prs_uint32("ptr ", ps, depth, &(r_l->ptr ));
+
+ if (r_l->ptr != 0)
+ {
+ switch (r_l->switch_value)
+ {
+ case 1:
+ {
+ net_io_netinfo_1("", &(r_l->logon.info1), ps, depth);
+ break;
+ }
+ case 2:
+ {
+ net_io_netinfo_2("", &(r_l->logon.info2), ps, depth);
+ break;
+ }
+ case 3:
+ {
+ net_io_netinfo_3("", &(r_l->logon.info3), ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(2,("net_io_r_logon_ctrl2: unsupported switch value %d\n",
+ r_l->switch_value));
+ break;
+ }
+ }
+ }
+
+ prs_uint32("status ", ps, depth, &(r_l->status ));
+}
+
+/*******************************************************************
+makes an NET_R_TRUST_DOM_LIST structure.
+********************************************************************/
+void make_r_trust_dom(NET_R_TRUST_DOM_LIST *r_t,
+ uint32 num_doms, char *dom_name)
+{
+ int i = 0;
+
+ if (r_t == NULL) return;
+
+ DEBUG(5,("make_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);
+ make_unistr2(&(r_t->uni_trust_dom_name[i]), domain_name, strlen(domain_name));
+ /* the use of UNISTR2 here is non-standard. */
+ r_t->uni_trust_dom_name[i].undoc = 0x1;
+ }
+
+ r_t->status = 0;
+}
+
+/*******************************************************************
+reads or writes an NET_R_TRUST_DOM_LIST structure.
+********************************************************************/
+void net_io_r_trust_dom(char *desc, NET_R_TRUST_DOM_LIST *r_t, prs_struct *ps, int depth)
+{
+ int i;
+ if (r_t == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_trust_dom");
+ depth++;
+
+ for (i = 0; i < MAX_TRUST_DOMS; i++)
+ {
+ if (r_t->uni_trust_dom_name[i].uni_str_len == 0) break;
+ smb_io_unistr2("", &(r_t->uni_trust_dom_name[i]), True, ps, depth);
+ }
+
+ prs_uint32("status", ps, depth, &(r_t->status));
+}
+
+
+/*******************************************************************
+reads or writes an NET_Q_TRUST_DOM_LIST structure.
+********************************************************************/
+void net_io_q_trust_dom(char *desc, NET_Q_TRUST_DOM_LIST *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_q_trust_dom");
+ depth++;
+
+ prs_uint32("ptr ", ps, depth, &(q_l->ptr ));
+ smb_io_unistr2 ("", &(q_l->uni_server_name), q_l->ptr, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("function_code", ps, depth, &(q_l->function_code));
+}
+
+/*******************************************************************
+makes an NET_Q_REQ_CHAL structure.
+********************************************************************/
+void make_q_req_chal(NET_Q_REQ_CHAL *q_c,
+ char *logon_srv, char *logon_clnt,
+ DOM_CHAL *clnt_chal)
+{
+ if (q_c == NULL) return;
+
+ DEBUG(5,("make_q_req_chal: %d\n", __LINE__));
+
+ q_c->undoc_buffer = 1; /* don't know what this buffer is */
+
+ make_unistr2(&(q_c->uni_logon_srv ), logon_srv , strlen(logon_srv ));
+ make_unistr2(&(q_c->uni_logon_clnt), logon_clnt, strlen(logon_clnt));
+
+ memcpy(q_c->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
+
+ DEBUG(5,("make_q_req_chal: %d\n", __LINE__));
+}
+
+/*******************************************************************
+reads or writes an NET_Q_REQ_CHAL structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "net_io_q_req_chal");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("undoc_buffer", ps, depth, &(q_c->undoc_buffer));
+
+ smb_io_unistr2("", &(q_c->uni_logon_srv), True, ps, depth); /* logon server unicode string */
+ smb_io_unistr2("", &(q_c->uni_logon_clnt), True, ps, depth); /* logon client unicode string */
+
+ old_align = ps->align;
+ ps->align = 0;
+ /* client challenge is _not_ aligned after the unicode strings */
+ smb_io_chal("", &(q_c->clnt_chal), ps, depth); /* client challenge */
+ ps->align = old_align;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_r_req_chal(char *desc, NET_R_REQ_CHAL *r_c, prs_struct *ps, int depth)
+{
+ if (r_c == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_req_chal");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_chal("", &(r_c->srv_chal), ps, depth); /* server challenge */
+
+ prs_uint32("status", ps, depth, &(r_c->status));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_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)
+{
+ if (q_a == NULL) return;
+
+ DEBUG(5,("make_q_auth_2: %d\n", __LINE__));
+
+ make_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,("make_q_auth_2: %d\n", __LINE__));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "net_io_q_auth_2");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_log_info ("", &(q_a->clnt_id), ps, depth); /* client identification info */
+ /* client challenge is _not_ aligned */
+ old_align = ps->align;
+ ps->align = 0;
+ smb_io_chal ("", &(q_a->clnt_chal), ps, depth); /* client-calculated credentials */
+ ps->align = old_align;
+ net_io_neg_flags("", &(q_a->clnt_flgs), ps, depth);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_r_auth_2(char *desc, NET_R_AUTH_2 *r_a, prs_struct *ps, int depth)
+{
+ if (r_a == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_auth_2");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_chal ("", &(r_a->srv_chal), ps, depth); /* server challenge */
+ net_io_neg_flags("", &(r_a->srv_flgs), ps, depth);
+
+ prs_uint32("status", ps, depth, &(r_a->status));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_q_srv_pwset(NET_Q_SRV_PWSET *q_s, char *logon_srv, char *acct_name,
+ uint16 sec_chan, char *comp_name, DOM_CRED *cred, char nt_cypher[16])
+{
+ if (q_s == NULL || cred == NULL) return;
+
+ DEBUG(5,("make_q_srv_pwset\n"));
+
+ make_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.
+********************************************************************/
+void net_io_q_srv_pwset(char *desc, NET_Q_SRV_PWSET *q_s, prs_struct *ps, int depth)
+{
+ if (q_s == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_q_srv_pwset");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_clnt_info("", &(q_s->clnt_id), ps, depth); /* client identification/authentication info */
+ prs_uint8s (False, "pwd", ps, depth, q_s->pwd, 16); /* new password - undocumented */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_r_srv_pwset(char *desc, NET_R_SRV_PWSET *r_s, prs_struct *ps, int depth)
+{
+ if (r_s == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_srv_pwset");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_cred("", &(r_s->srv_cred), ps, depth); /* server challenge */
+
+ prs_uint32("status", ps, depth, &(r_s->status));
+}
+
+
+/*************************************************************************
+ make DOM_SID2 array from a string containing multiple sids
+ *************************************************************************/
+static int make_dom_sid2s(char *sids_str, DOM_SID2 *sids, int max_sids)
+{
+ char *ptr;
+ pstring s2;
+ int count;
+
+ DEBUG(4,("make_dom_sid2s: %s\n", sids_str ? sids_str:""));
+
+ if (sids_str == NULL || *sids_str == 0) return 0;
+
+ for (count = 0, ptr = sids_str;
+ next_token(&ptr, s2, NULL, sizeof(s2)) && count < max_sids;
+ count++)
+ {
+ DOM_SID tmpsid;
+ string_to_sid(&tmpsid, s2);
+ make_dom_sid2(&sids[count], &tmpsid);
+ }
+
+ return count;
+}
+
+/*******************************************************************
+reads or writes an NET_ID_INFO_1 structure.
+********************************************************************/
+static void net_io_id_info1(char *desc, NET_ID_INFO_1 *id, prs_struct *ps, int depth)
+{
+ if (id == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_id_info1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_id_info1", ps, depth, &(id->ptr_id_info1));
+
+ if (id->ptr_id_info1 != 0)
+ {
+ smb_io_unihdr("unihdr", &(id->hdr_domain_name), ps, depth);
+
+ prs_uint32("param_ctrl", ps, depth, &(id->param_ctrl));
+ smb_io_logon_id("", &(id->logon_id), ps, depth);
+
+ smb_io_unihdr("unihdr", &(id->hdr_user_name ), ps, depth);
+ smb_io_unihdr("unihdr", &(id->hdr_wksta_name ), ps, depth);
+
+ smb_io_owf_info("", &(id->lm_owf), ps, depth);
+ smb_io_owf_info("", &(id->nt_owf), ps, depth);
+
+ smb_io_unistr2("unistr2", &(id->uni_domain_name), id->hdr_domain_name.buffer, ps, depth);
+ smb_io_unistr2("unistr2", &(id->uni_user_name ), id->hdr_user_name.buffer, ps, depth);
+ smb_io_unistr2("unistr2", &(id->uni_wksta_name ), id->hdr_wksta_name.buffer, ps, depth);
+ }
+}
+
+/*******************************************************************
+makes 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 make_id_info2(NET_ID_INFO_2 *id, char *domain_name,
+ uint32 param_ctrl, uint32 log_id_low, uint32 log_id_high,
+ char *user_name, char *wksta_name,
+ unsigned char lm_challenge[8],
+ unsigned char lm_chal_resp[24],
+ unsigned char nt_chal_resp[24])
+{
+ int len_domain_name = strlen(domain_name);
+ int len_user_name = strlen(user_name );
+ int len_wksta_name = strlen(wksta_name );
+ int nt_chal_resp_len = ((nt_chal_resp != NULL) ? 24 : 0);
+ int lm_chal_resp_len = ((lm_chal_resp != NULL) ? 24 : 0);
+ unsigned char lm_owf[24];
+ unsigned char nt_owf[24];
+
+ if (id == NULL) return;
+
+ DEBUG(5,("make_id_info2: %d\n", __LINE__));
+
+ id->ptr_id_info2 = 1;
+
+ make_uni_hdr(&(id->hdr_domain_name), len_domain_name, len_domain_name, 4);
+
+ id->param_ctrl = param_ctrl;
+ make_logon_id(&(id->logon_id), log_id_low, log_id_high);
+
+ make_uni_hdr(&(id->hdr_user_name ), len_user_name , len_user_name , 4);
+ make_uni_hdr(&(id->hdr_wksta_name ), len_wksta_name , len_wksta_name , 4);
+
+ if (nt_chal_resp)
+ {
+ /* oops. can only send what-ever-it-is direct */
+ memcpy(nt_owf, nt_chal_resp, 24);
+ nt_chal_resp = nt_owf;
+ }
+ if (lm_chal_resp)
+ {
+ /* oops. can only send what-ever-it-is direct */
+ memcpy(lm_owf, lm_chal_resp, 24);
+ lm_chal_resp = lm_owf;
+ }
+
+ memcpy(id->lm_chal, lm_challenge, sizeof(id->lm_chal));
+ make_str_hdr(&(id->hdr_nt_chal_resp), 24, nt_chal_resp_len, nt_chal_resp != NULL ? 1 : 0);
+ make_str_hdr(&(id->hdr_lm_chal_resp), 24, lm_chal_resp_len, lm_chal_resp != NULL ? 1 : 0);
+
+ make_unistr2(&(id->uni_domain_name), domain_name, len_domain_name);
+ make_unistr2(&(id->uni_user_name ), user_name , len_user_name );
+ make_unistr2(&(id->uni_wksta_name ), wksta_name , len_wksta_name );
+
+ make_string2(&(id->nt_chal_resp ), (char *)nt_chal_resp , nt_chal_resp_len);
+ make_string2(&(id->lm_chal_resp ), (char *)lm_chal_resp , lm_chal_resp_len);
+}
+
+/*******************************************************************
+reads or writes an NET_ID_INFO_2 structure.
+********************************************************************/
+static void net_io_id_info2(char *desc, NET_ID_INFO_2 *id, prs_struct *ps, int depth)
+{
+ if (id == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_id_info2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_id_info2", ps, depth, &(id->ptr_id_info2));
+
+ if (id->ptr_id_info2 != 0)
+ {
+ smb_io_unihdr("unihdr", &(id->hdr_domain_name), ps, depth);
+
+ prs_uint32("param_ctrl", ps, depth, &(id->param_ctrl));
+ smb_io_logon_id("", &(id->logon_id), ps, depth);
+
+ smb_io_unihdr("unihdr", &(id->hdr_user_name ), ps, depth);
+ smb_io_unihdr("unihdr", &(id->hdr_wksta_name ), ps, depth);
+
+ prs_uint8s (False, "lm_chal", ps, depth, id->lm_chal, 8); /* lm 8 byte challenge */
+
+ smb_io_strhdr("hdr_nt_chal_resp", &(id->hdr_nt_chal_resp ), ps, depth);
+ smb_io_strhdr("hdr_lm_chal_resp", &(id->hdr_lm_chal_resp ), ps, depth);
+
+ smb_io_unistr2("uni_domain_name", &(id->uni_domain_name), id->hdr_domain_name .buffer, ps, depth);
+ smb_io_unistr2("uni_user_name ", &(id->uni_user_name ), id->hdr_user_name .buffer, ps, depth);
+ smb_io_unistr2("uni_wksta_name ", &(id->uni_wksta_name ), id->hdr_wksta_name .buffer, ps, depth);
+ smb_io_string2("nt_chal_resp" , &(id->nt_chal_resp) , id->hdr_nt_chal_resp.buffer, ps, depth);
+ smb_io_string2("lm_chal_resp" , &(id->lm_chal_resp) , id->hdr_lm_chal_resp.buffer, ps, depth);
+ }
+}
+
+
+/*******************************************************************
+makes a DOM_SAM_INFO structure.
+********************************************************************/
+void make_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, uint16 validation_level)
+{
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_info: %d\n", __LINE__));
+
+ make_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;
+ sam->validation_level = validation_level;
+}
+
+/*******************************************************************
+reads or writes a DOM_SAM_INFO structure.
+********************************************************************/
+static void net_io_id_info_ctr(char *desc, NET_ID_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_sam_info");
+ depth++;
+
+ /* don't 4-byte align here! */
+
+ prs_uint16("switch_value ", ps, depth, &(ctr->switch_value));
+
+ switch (ctr->switch_value)
+ {
+ case 1:
+ {
+ net_io_id_info1("", &(ctr->auth.id1), ps, depth);
+ break;
+ }
+ case 2:
+ {
+ net_io_id_info2("", &(ctr->auth.id2), ps, depth);
+ break;
+ }
+ default:
+ {
+ /* PANIC! */
+ DEBUG(4,("smb_io_sam_info: unknown switch_value!\n"));
+ break;
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a DOM_SAM_INFO structure.
+********************************************************************/
+static void smb_io_sam_info(char *desc, DOM_SAM_INFO *sam, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_sam_info");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_clnt_info2("", &(sam->client ), ps, depth);
+
+ prs_uint32("ptr_rtn_cred ", ps, depth, &(sam->ptr_rtn_cred));
+ smb_io_cred ("", &(sam->rtn_cred), ps, depth);
+
+ prs_uint16("logon_level ", ps, depth, &(sam->logon_level ));
+
+ if (sam->logon_level != 0 && sam->ctr != NULL)
+ {
+ net_io_id_info_ctr("logon_info", sam->ctr, ps, depth);
+ }
+
+ prs_uint16("validation_level", ps, depth, &(sam->validation_level));
+}
+
+/*************************************************************************
+ make_net_user_info3
+ *************************************************************************/
+void make_net_user_info3(NET_USER_INFO_3 *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,
+
+ char *user_name,
+ char *full_name,
+ char *logon_script,
+ char *profile_path,
+ char *home_dir,
+ char *dir_drive,
+
+ uint16 logon_count,
+ uint16 bad_pw_count,
+
+ uint32 user_id,
+ uint32 group_id,
+ uint32 num_groups,
+ DOM_GID *gids,
+ uint32 user_flgs,
+
+ char sess_key[16],
+
+ 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;
+
+ int len_user_name = strlen(user_name );
+ int len_full_name = strlen(full_name );
+ int len_logon_script = strlen(logon_script);
+ int len_profile_path = strlen(profile_path);
+ int len_home_dir = strlen(home_dir );
+ int len_dir_drive = strlen(dir_drive );
+
+ int len_logon_srv = strlen(logon_srv);
+ int len_logon_dom = strlen(logon_dom);
+
+ usr->ptr_user_info = 1; /* yes, we're bothering to put USER_INFO data here */
+
+ 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;
+
+ make_uni_hdr(&(usr->hdr_user_name ), len_user_name , len_user_name , 4);
+ make_uni_hdr(&(usr->hdr_full_name ), len_full_name , len_full_name , 4);
+ make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4);
+ make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4);
+ make_uni_hdr(&(usr->hdr_home_dir ), len_home_dir , len_home_dir , 4);
+ make_uni_hdr(&(usr->hdr_dir_drive ), len_dir_drive , len_dir_drive , 4);
+
+ usr->logon_count = logon_count;
+ usr->bad_pw_count = bad_pw_count;
+
+ usr->user_id = user_id;
+ usr->group_id = group_id;
+ 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
+ {
+ bzero(usr->user_sess_key, sizeof(usr->user_sess_key));
+ }
+
+ make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4);
+ make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4);
+
+ usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
+
+ bzero(usr->padding, sizeof(usr->padding));
+
+ num_other_sids = make_dom_sid2s(other_sids, usr->other_sids, LSA_MAX_SIDS);
+
+ usr->num_other_sids = num_other_sids;
+ usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0;
+
+ make_unistr2(&(usr->uni_user_name ), user_name , len_user_name );
+ make_unistr2(&(usr->uni_full_name ), full_name , len_full_name );
+ make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script);
+ make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path);
+ make_unistr2(&(usr->uni_home_dir ), home_dir , len_home_dir );
+ make_unistr2(&(usr->uni_dir_drive ), dir_drive , len_dir_drive );
+
+ usr->num_groups2 = num_groups;
+
+ SMB_ASSERT_ARRAY(usr->gids, num_groups);
+
+ for (i = 0; i < num_groups; i++)
+ {
+ usr->gids[i] = gids[i];
+ }
+
+ make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv);
+ make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom);
+
+ make_dom_sid2(&(usr->dom_sid), dom_sid);
+ /* "other" sids are set up above */
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void net_io_user_info3(char *desc, NET_USER_INFO_3 *usr, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (usr == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_lsa_user_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_user_info ", ps, depth, &(usr->ptr_user_info));
+
+ if (usr->ptr_user_info != 0)
+ {
+ smb_io_time("time", &(usr->logon_time) , ps, depth); /* logon time */
+ smb_io_time("time", &(usr->logoff_time) , ps, depth); /* logoff time */
+ smb_io_time("time", &(usr->kickoff_time) , ps, depth); /* kickoff time */
+ smb_io_time("time", &(usr->pass_last_set_time) , ps, depth); /* password last set time */
+ smb_io_time("time", &(usr->pass_can_change_time) , ps, depth); /* password can change time */
+ smb_io_time("time", &(usr->pass_must_change_time), ps, depth); /* password must change time */
+
+ smb_io_unihdr("unihdr", &(usr->hdr_user_name) , ps, depth); /* username unicode string header */
+ smb_io_unihdr("unihdr", &(usr->hdr_full_name) , ps, depth); /* user's full name unicode string header */
+ smb_io_unihdr("unihdr", &(usr->hdr_logon_script), ps, depth); /* logon script unicode string header */
+ smb_io_unihdr("unihdr", &(usr->hdr_profile_path), ps, depth); /* profile path unicode string header */
+ smb_io_unihdr("unihdr", &(usr->hdr_home_dir) , ps, depth); /* home directory unicode string header */
+ smb_io_unihdr("unihdr", &(usr->hdr_dir_drive) , ps, depth); /* home directory drive unicode string header */
+
+ prs_uint16("logon_count ", ps, depth, &(usr->logon_count )); /* logon count */
+ prs_uint16("bad_pw_count ", ps, depth, &(usr->bad_pw_count)); /* bad password count */
+
+ prs_uint32("user_id ", ps, depth, &(usr->user_id )); /* User ID */
+ prs_uint32("group_id ", ps, depth, &(usr->group_id )); /* Group ID */
+ prs_uint32("num_groups ", ps, depth, &(usr->num_groups )); /* num groups */
+ prs_uint32("buffer_groups ", ps, depth, &(usr->buffer_groups)); /* undocumented buffer pointer to groups. */
+ prs_uint32("user_flgs ", ps, depth, &(usr->user_flgs )); /* user flags */
+
+ prs_uint8s (False, "user_sess_key", ps, depth, usr->user_sess_key, 16); /* unused user session key */
+
+ smb_io_unihdr("unihdr", &(usr->hdr_logon_srv), ps, depth); /* logon server unicode string header */
+ smb_io_unihdr("unihdr", &(usr->hdr_logon_dom), ps, depth); /* logon domain unicode string header */
+
+ prs_uint32("buffer_dom_id ", ps, depth, &(usr->buffer_dom_id)); /* undocumented logon domain id pointer */
+ prs_uint8s (False, "padding ", ps, depth, usr->padding, 40); /* unused padding bytes? */
+
+ prs_uint32("num_other_sids", ps, depth, &(usr->num_other_sids)); /* 0 - num_sids */
+ prs_uint32("buffer_other_sids", ps, depth, &(usr->buffer_other_sids)); /* NULL - undocumented pointer to SIDs. */
+
+ smb_io_unistr2("unistr2", &(usr->uni_user_name) , usr->hdr_user_name .buffer, ps, depth); /* username unicode string */
+ smb_io_unistr2("unistr2", &(usr->uni_full_name) , usr->hdr_full_name .buffer, ps, depth); /* user's full name unicode string */
+ smb_io_unistr2("unistr2", &(usr->uni_logon_script), usr->hdr_logon_script.buffer, ps, depth); /* logon script unicode string */
+ smb_io_unistr2("unistr2", &(usr->uni_profile_path), usr->hdr_profile_path.buffer, ps, depth); /* profile path unicode string */
+ smb_io_unistr2("unistr2", &(usr->uni_home_dir) , usr->hdr_home_dir .buffer, ps, depth); /* home directory unicode string */
+ smb_io_unistr2("unistr2", &(usr->uni_dir_drive) , usr->hdr_dir_drive .buffer, ps, depth); /* home directory drive unicode string */
+
+ prs_align(ps);
+ prs_uint32("num_groups2 ", ps, depth, &(usr->num_groups2)); /* num groups */
+ SMB_ASSERT_ARRAY(usr->gids, usr->num_groups2);
+ for (i = 0; i < usr->num_groups2; i++)
+ {
+ smb_io_gid("", &(usr->gids[i]), ps, depth); /* group info */
+ }
+
+ smb_io_unistr2("unistr2", &( usr->uni_logon_srv), usr->hdr_logon_srv.buffer, ps, depth); /* logon server unicode string */
+ smb_io_unistr2("unistr2", &( usr->uni_logon_dom), usr->hdr_logon_srv.buffer, ps, depth); /* logon domain unicode string */
+
+ smb_io_dom_sid2("", &(usr->dom_sid), ps, depth); /* domain SID */
+
+ SMB_ASSERT_ARRAY(usr->other_sids, usr->num_other_sids);
+
+ for (i = 0; i < usr->num_other_sids; i++)
+ {
+ smb_io_dom_sid2("", &(usr->other_sids[i]), ps, depth); /* other domain SIDs */
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_q_sam_logon(char *desc, NET_Q_SAM_LOGON *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_q_sam_logon");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_sam_info("", &(q_l->sam_id), ps, depth); /* domain SID */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_r_sam_logon(char *desc, NET_R_SAM_LOGON *r_l, prs_struct *ps, int depth)
+{
+ if (r_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_logon");
+ depth++;
+
+ prs_uint32("buffer_creds", ps, depth, &(r_l->buffer_creds)); /* undocumented buffer pointer */
+ smb_io_cred("", &(r_l->srv_creds), ps, depth); /* server credentials. server time stamp appears to be ignored. */
+
+ prs_uint16("switch_value", ps, depth, &(r_l->switch_value));
+ prs_align(ps);
+
+ if (r_l->switch_value != 0)
+ {
+ net_io_user_info3("", r_l->user, ps, depth);
+ }
+
+ prs_uint32("auth_resp ", ps, depth, &(r_l->auth_resp)); /* 1 - Authoritative response; 0 - Non-Auth? */
+
+ prs_uint32("status ", ps, depth, &(r_l->status));
+
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_q_sam_logoff(char *desc, NET_Q_SAM_LOGOFF *q_l, prs_struct *ps, int depth)
+{
+ if (q_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_q_sam_logoff");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_sam_info("", &(q_l->sam_id), ps, depth); /* domain SID */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void net_io_r_sam_logoff(char *desc, NET_R_SAM_LOGOFF *r_l, prs_struct *ps, int depth)
+{
+ if (r_l == NULL) return;
+
+ prs_debug(ps, depth, desc, "net_io_r_sam_logoff");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("buffer_creds", ps, depth, &(r_l->buffer_creds)); /* undocumented buffer pointer */
+ smb_io_cred("", &(r_l->srv_creds), ps, depth); /* server credentials. server time stamp appears to be ignored. */
+
+ prs_uint32("status ", ps, depth, &(r_l->status));
+}
+
+
diff --git a/source/rpc_parse/parse_prs.c b/source/rpc_parse/parse_prs.c
new file mode 100644
index 00000000000..024ac88b18f
--- /dev/null
+++ b/source/rpc_parse/parse_prs.c
@@ -0,0 +1,276 @@
+/*
+ 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
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+extern int DEBUGLEVEL;
+
+#include "includes.h"
+
+
+/*******************************************************************
+ 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->offset, fn_name, desc));
+}
+
+/*******************************************************************
+ initialise a parse structure
+ ********************************************************************/
+void prs_init(prs_struct *ps, uint32 size,
+ uint8 align, uint32 margin,
+ BOOL io)
+{
+ ps->io = io;
+ ps->align = align;
+ ps->offset = 0;
+
+ ps->data = NULL;
+ mem_buf_init(&(ps->data), margin);
+
+ if (size != 0)
+ {
+ mem_alloc_data(ps->data, size);
+ ps->data->offset.start = 0;
+ ps->data->offset.end = 0xffffffff;
+ }
+}
+
+/*******************************************************************
+ initialise a parse structure
+ ********************************************************************/
+void prs_mem_free(prs_struct *ps)
+{
+ mem_buf_free(&(ps->data));
+}
+
+/*******************************************************************
+ align a pointer to a multiple of align_offset bytes. looks like it
+ will work for offsets of 0, 2 and 4...
+ ********************************************************************/
+void prs_align(prs_struct *ps)
+{
+ int mod = ps->offset & (ps->align-1);
+ if (ps->align != 0 && mod != 0)
+ {
+ ps->offset += ps->align - mod;
+ }
+}
+
+/*******************************************************************
+ attempt, if appropriate, to grow a data buffer.
+
+ depends on the data stream mode (io)
+ ********************************************************************/
+BOOL prs_grow(prs_struct *ps)
+{
+ return mem_grow_data(&(ps->data), ps->io, ps->offset, False);
+}
+
+
+/*******************************************************************
+ stream a uint8
+ ********************************************************************/
+BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_CVAL(name, depth, ps->offset, ps->io, q, *data8)
+ ps->offset += 1;
+
+ return True;
+}
+
+/*******************************************************************
+ stream a uint16
+ ********************************************************************/
+BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_SVAL(name, depth, ps->offset, ps->io, q, *data16)
+ ps->offset += 2;
+
+ return True;
+}
+
+/*******************************************************************
+ stream a uint32
+ ********************************************************************/
+BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_IVAL(name, depth, ps->offset, ps->io, q, *data32)
+ ps->offset += 4;
+
+ 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)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_PCVAL(charmode, name, depth, ps->offset, ps->io, q, data8s, len)
+ ps->offset += len;
+
+ 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)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_PIVAL(charmode, name, depth, ps->offset, ps->io, q, data32s, len)
+ ps->offset += len * sizeof(uint32);
+
+ return True;
+}
+
+/******************************************************************
+ stream a "not" unicode string, length/buffer specified separately,
+ in byte chars
+ ********************************************************************/
+BOOL prs_uninotstr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNINOTSTR2 *str)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_PSVAL(charmode, name, depth, ps->offset, ps->io, q, str->buffer, str->uni_max_len)
+ ps->offset += str->uni_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)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_PCVAL(charmode, name, depth, ps->offset, ps->io, q, str->buffer, str->str_max_len)
+ ps->offset += str->str_str_len * sizeof(uint8);
+
+ return True;
+}
+
+/******************************************************************
+ stream a unicode string, length/buffer specified separately,
+ in uint16 chars.
+ ********************************************************************/
+BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ if (q == NULL) return False;
+
+ DBG_RW_PSVAL(charmode, name, depth, ps->offset, ps->io, q, str->buffer, str->uni_max_len)
+ ps->offset += str->uni_str_len * sizeof(uint16);
+
+ return True;
+}
+
+/*******************************************************************
+ stream a unicode null-terminated string
+ ********************************************************************/
+BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ int i = 0;
+ uint8 *start = (uint8*)q;
+
+ if (q == NULL) return False;
+
+ do
+ {
+ RW_SVAL(ps->io, q, str->buffer[i],0);
+ q += 2;
+ i++;
+
+ } while ((i < sizeof(str->buffer) / sizeof(str->buffer[0])) &&
+ (str->buffer[i] != 0));
+
+ ps->offset += i*2;
+
+ dump_data(5+depth, (char *)start, ps->offset);
+
+ return True;
+}
+
+/*******************************************************************
+ stream a null-terminated string. len is strlen, and therefore does
+ not include the null-termination character.
+
+ len == 0 indicates variable length string
+ (up to max size of pstring - 1024 chars).
+
+ ********************************************************************/
+BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, uint16 len)
+{
+ char *q = mem_data(&(ps->data), ps->offset);
+ uint8 *start = (uint8*)q;
+ int i = -1; /* start off at zero after 1st i++ */
+
+ if (q == NULL) return False;
+
+ do
+ {
+ i++;
+
+ if (i < len || len == 0)
+ {
+ RW_CVAL(ps->io, q, str[i],0);
+ }
+ else
+ {
+ uint8 dummy = 0;
+ RW_CVAL(ps->io, q, dummy,0);
+ }
+
+ q++;
+
+ } while (i < sizeof(pstring) && (len == 0 ? str[i] != 0 : i < len) );
+
+ ps->offset += i+1;
+
+ dump_data(5+depth, (char *)start, ps->offset);
+
+ return True;
+}
+
diff --git a/source/rpc_parse/parse_reg.c b/source/rpc_parse/parse_reg.c
new file mode 100644
index 00000000000..6b464645e51
--- /dev/null
+++ b/source/rpc_parse/parse_reg.c
@@ -0,0 +1,264 @@
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_q_open_policy(char *desc, REG_Q_OPEN_POLICY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_q_open_policy");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr ", ps, depth, &(r_q->ptr ));
+ if (r_q->ptr != 0)
+ {
+ prs_uint16("unknown_0", ps, depth, &(r_q->unknown_0));
+ prs_uint32("level ", ps, depth, &(r_q->level ));
+ prs_uint16("unknown_1", ps, depth, &(r_q->unknown_1));
+ }
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_r_open_policy(char *desc, REG_R_OPEN_POLICY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_r_open_policy");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(r_r->pol), ps, depth);
+
+ prs_uint32("status", ps, depth, &(r_r->status));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_q_close(char *desc, REG_Q_CLOSE *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_q_unknown_1");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(q_u->pol), ps, depth);
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_r_close(char *desc, REG_R_CLOSE *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_r_unknown_1");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(r_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_q_info(char *desc, REG_Q_INFO *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_q_info");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(r_q->pol), ps, depth);
+ smb_io_unihdr ("", &(r_q->hdr_type), ps, depth);
+ smb_io_unistr2("", &(r_q->uni_type), r_q->hdr_type.buffer, ps, depth);
+
+ prs_uint32("ptr1", ps, depth, &(r_q->ptr1));
+
+ if (r_q->ptr1 != 0)
+ {
+ smb_io_time("", &(r_q->time), ps, depth);
+ prs_uint8 ("major_version1", ps, depth, &(r_q->major_version1));
+ prs_uint8 ("minor_version1", ps, depth, &(r_q->minor_version1));
+ prs_uint8s(False, "pad1", ps, depth, r_q->pad1, sizeof(r_q->pad1));
+ }
+
+ prs_uint32("ptr2", ps, depth, &(r_q->ptr2));
+
+ if (r_q->ptr2 != 0)
+ {
+ prs_uint8 ("major_version2", ps, depth, &(r_q->major_version2));
+ prs_uint8 ("minor_version2", ps, depth, &(r_q->minor_version2));
+ prs_uint8s(False, "pad2", ps, depth, r_q->pad2, sizeof(r_q->pad2));
+ }
+
+ prs_uint32("ptr3", ps, depth, &(r_q->ptr3));
+
+ if (r_q->ptr3 != 0)
+ {
+ prs_uint32("unknown", ps, depth, &(r_q->unknown));
+ }
+}
+
+
+/*******************************************************************
+creates a structure.
+********************************************************************/
+void make_reg_r_info(REG_R_INFO *r_r,
+ uint32 level, char *os_type,
+ uint32 unknown_0, uint32 unknown_1,
+ uint32 status)
+{
+ int type_len = strlen(os_type);
+
+ r_r->ptr1 = 1;
+ r_r->level = level;
+
+ r_r->ptr_type = 1;
+ make_uninotstr2(&(r_r->uni_type), os_type, type_len);
+
+ r_r->ptr2 = 1;
+ r_r->unknown_0 = unknown_0;
+
+ r_r->ptr3 = 1;
+ r_r->unknown_1 = unknown_1;
+
+ r_r->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_r_info(char *desc, REG_R_INFO *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_r_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr1", ps, depth, &(r_r->ptr1));
+
+ if (r_r->ptr1 != 0)
+ {
+ prs_uint32("level", ps, depth, &(r_r->level));
+
+ prs_uint32("ptr_type", ps, depth, &(r_r->ptr_type));
+ smb_io_uninotstr2("", &(r_r->uni_type), r_r->ptr_type, ps, depth);
+ prs_align(ps);
+
+ prs_uint32("ptr2", ps, depth, &(r_r->ptr2));
+
+ if (r_r->ptr2 != 0)
+ {
+ prs_uint32("unknown_0", ps, depth, &(r_r->unknown_0));
+ }
+
+ prs_uint32("ptr3", ps, depth, &(r_r->ptr3));
+
+ if (r_r->ptr3 != 0)
+ {
+ prs_uint32("unknown_1", ps, depth, &(r_r->unknown_1));
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_r->status));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_q_open_entry(char *desc, REG_Q_OPEN_ENTRY *r_q, prs_struct *ps, int depth)
+{
+ if (r_q == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_q_entry");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(r_q->pol), ps, depth);
+ smb_io_unihdr ("", &(r_q->hdr_name), ps, depth);
+ smb_io_unistr2("", &(r_q->uni_name), r_q->hdr_name.buffer, ps, depth);
+
+ prs_uint32("unknown_0", ps, depth, &(r_q->unknown_0));
+ prs_uint16("unknown_1", ps, depth, &(r_q->unknown_1));
+ prs_uint16("unknown_2", ps, depth, &(r_q->unknown_2));
+}
+
+
+/*******************************************************************
+creates a structure.
+********************************************************************/
+void make_reg_r_open_entry(REG_R_OPEN_ENTRY *r_r,
+ POLICY_HND *pol, uint32 status)
+{
+ if (r_r == NULL) return;
+
+ memcpy(&(r_r->pol), pol, sizeof(r_r->pol));
+ r_r->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void reg_io_r_open_entry(char *desc, REG_R_OPEN_ENTRY *r_r, prs_struct *ps, int depth)
+{
+ if (r_r == NULL) return;
+
+ prs_debug(ps, depth, desc, "reg_io_r_open_entry");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("", &(r_r->pol), ps, depth);
+
+ prs_uint32("status", ps, depth, &(r_r->status));
+}
+
diff --git a/source/rpc_parse/parse_rpc.c b/source/rpc_parse/parse_rpc.c
new file mode 100644
index 00000000000..ac01e7f0b13
--- /dev/null
+++ b/source/rpc_parse/parse_rpc.c
@@ -0,0 +1,529 @@
+
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+interface/version dce/rpc pipe identification
+********************************************************************/
+
+#define TRANS_SYNT_V2 \
+{ \
+ { \
+ 0x04, 0x5d, 0x88, 0x8a, \
+ 0xeb, 0x1c, 0xc9, 0x11, \
+ 0x9f, 0xe8, 0x08, 0x00, \
+ 0x2b, 0x10, 0x48, 0x60 \
+ }, 0x02 \
+} \
+
+#define SYNT_NETLOGON_V2 \
+{ \
+ { \
+ 0x04, 0x5d, 0x88, 0x8a, \
+ 0xeb, 0x1c, 0xc9, 0x11, \
+ 0x9f, 0xe8, 0x08, 0x00, \
+ 0x2b, 0x10, 0x48, 0x60 \
+ }, 0x02 \
+} \
+
+#define SYNT_WKSSVC_V1 \
+{ \
+ { \
+ 0x98, 0xd0, 0xff, 0x6b, \
+ 0x12, 0xa1, 0x10, 0x36, \
+ 0x98, 0x33, 0x46, 0xc3, \
+ 0xf8, 0x7e, 0x34, 0x5a \
+ }, 0x01 \
+} \
+
+#define SYNT_SRVSVC_V3 \
+{ \
+ { \
+ 0xc8, 0x4f, 0x32, 0x4b, \
+ 0x70, 0x16, 0xd3, 0x01, \
+ 0x12, 0x78, 0x5a, 0x47, \
+ 0xbf, 0x6e, 0xe1, 0x88 \
+ }, 0x03 \
+} \
+
+#define SYNT_LSARPC_V0 \
+{ \
+ { \
+ 0x78, 0x57, 0x34, 0x12, \
+ 0x34, 0x12, 0xcd, 0xab, \
+ 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0x89, 0xab \
+ }, 0x00 \
+} \
+
+#define SYNT_SAMR_V1 \
+{ \
+ { \
+ 0x78, 0x57, 0x34, 0x12, \
+ 0x34, 0x12, 0xcd, 0xab, \
+ 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0x89, 0xac \
+ }, 0x01 \
+} \
+
+#define SYNT_NETLOGON_V1 \
+{ \
+ { \
+ 0x78, 0x56, 0x34, 0x12, \
+ 0x34, 0x12, 0xcd, 0xab, \
+ 0xef, 0x00, 0x01, 0x23, \
+ 0x45, 0x67, 0xcf, 0xfb \
+ }, 0x01 \
+} \
+
+#define SYNT_WINREG_V1 \
+{ \
+ { \
+ 0x01, 0xd0, 0x8c, 0x33, \
+ 0x44, 0x22, 0xf1, 0x31, \
+ 0xaa, 0xaa, 0x90, 0x00, \
+ 0x38, 0x00, 0x10, 0x03 \
+ }, 0x01 \
+} \
+
+#define SYNT_NONE_V0 \
+{ \
+ { \
+ 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00 \
+ }, 0x00 \
+} \
+
+/* pipe string names */
+#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"
+
+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 },
+ { NULL , SYNT_NONE_V0 , NULL , SYNT_NONE_V0 }
+};
+
+/*******************************************************************
+creates an RPC_HDR structure.
+********************************************************************/
+void make_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 flags,
+ uint32 call_id, int data_len, int auth_len)
+{
+ if (hdr == NULL) return;
+
+ 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 = 0x10; /* 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.
+********************************************************************/
+void smb_io_rpc_hdr(char *desc, RPC_HDR *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr");
+ depth++;
+
+ prs_uint8 ("major ", ps, depth, &(rpc->major));
+ prs_uint8 ("minor ", ps, depth, &(rpc->minor));
+ prs_uint8 ("pkt_type ", ps, depth, &(rpc->pkt_type));
+ prs_uint8 ("flags ", ps, depth, &(rpc->flags));
+ prs_uint32("pack_type ", ps, depth, &(rpc->pack_type));
+ prs_uint16("frag_len ", ps, depth, &(rpc->frag_len));
+ prs_uint16("auth_len ", ps, depth, &(rpc->auth_len));
+ prs_uint32("call_id ", ps, depth, &(rpc->call_id));
+}
+
+/*******************************************************************
+reads or writes an RPC_IFACE structure.
+********************************************************************/
+static void smb_io_rpc_iface(char *desc, RPC_IFACE *ifc, prs_struct *ps, int depth)
+{
+ if (ifc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_iface");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint8s (False, "data ", ps, depth, ifc->data, sizeof(ifc->data));
+ prs_uint32 ( "version", ps, depth, &(ifc->version));
+}
+
+/*******************************************************************
+creates an RPC_ADDR_STR structure.
+********************************************************************/
+static void make_rpc_addr_str(RPC_ADDR_STR *str, char *name)
+{
+ if (str == NULL || name == NULL) return;
+
+ str->len = strlen(name) + 1;
+ fstrcpy(str->str, name);
+}
+
+/*******************************************************************
+reads or writes an RPC_ADDR_STR structure.
+********************************************************************/
+static void smb_io_rpc_addr_str(char *desc, RPC_ADDR_STR *str, prs_struct *ps, int depth)
+{
+ if (str == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_addr_str");
+ depth++;
+ prs_align(ps);
+
+ prs_uint16 ( "len", ps, depth, &(str->len));
+ prs_uint8s (True, "str", ps, depth, (uchar*)str->str, str->len);
+}
+
+/*******************************************************************
+creates an RPC_HDR_BBA structure.
+********************************************************************/
+static void make_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid)
+{
+ if (bba == NULL) return;
+
+ 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 void smb_io_rpc_hdr_bba(char *desc, RPC_HDR_BBA *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_bba");
+ depth++;
+
+ prs_uint16("max_tsize", ps, depth, &(rpc->max_tsize));
+ prs_uint16("max_rsize", ps, depth, &(rpc->max_rsize));
+ prs_uint32("assoc_gid", ps, depth, &(rpc->assoc_gid));
+}
+
+/*******************************************************************
+creates an RPC_HDR_RB structure.
+********************************************************************/
+void make_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)
+{
+ if (rpc == NULL) return;
+
+ make_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 */
+ memcpy(&(rpc->abstract), abstract, sizeof(rpc->abstract));
+
+ /* num and vers. of interface to use for replies */
+ memcpy(&(rpc->transfer), transfer, sizeof(rpc->transfer));
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_RB structure.
+********************************************************************/
+void smb_io_rpc_hdr_rb(char *desc, RPC_HDR_RB *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_rb");
+ depth++;
+
+ smb_io_rpc_hdr_bba("", &(rpc->bba), ps, depth);
+
+ prs_uint32("num_elements", ps, depth, &(rpc->num_elements));
+ prs_uint16("context_id ", ps, depth, &(rpc->context_id ));
+ prs_uint8 ("num_syntaxes", ps, depth, &(rpc->num_syntaxes));
+
+ smb_io_rpc_iface("", &(rpc->abstract), ps, depth);
+ smb_io_rpc_iface("", &(rpc->transfer), ps, depth);
+}
+
+/*******************************************************************
+creates an RPC_RESULTS structure.
+
+lkclXXXX only one reason at the moment!
+
+********************************************************************/
+static void make_rpc_results(RPC_RESULTS *res,
+ uint8 num_results, uint16 result, uint16 reason)
+{
+ if (res == NULL) return;
+
+ 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 void smb_io_rpc_results(char *desc, RPC_RESULTS *res, prs_struct *ps, int depth)
+{
+ if (res == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_results");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint8 ("num_results", ps, depth, &(res->num_results));
+
+ prs_align(ps);
+
+ prs_uint16("result ", ps, depth, &(res->result ));
+ prs_uint16("reason ", ps, depth, &(res->reason ));
+}
+
+/*******************************************************************
+creates an RPC_HDR_BA structure.
+
+lkclXXXX only one reason at the moment!
+
+********************************************************************/
+void make_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)
+{
+ if (rpc == NULL || transfer == NULL || pipe_addr == NULL) return;
+
+ make_rpc_hdr_bba (&(rpc->bba ), max_tsize, max_rsize, assoc_gid);
+ make_rpc_addr_str(&(rpc->addr), pipe_addr);
+ make_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.
+********************************************************************/
+void smb_io_rpc_hdr_ba(char *desc, RPC_HDR_BA *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_ba");
+ depth++;
+
+ smb_io_rpc_hdr_bba ("", &(rpc->bba) , ps, depth);
+ smb_io_rpc_addr_str("", &(rpc->addr) , ps, depth);
+ smb_io_rpc_results ("", &(rpc->res) , ps, depth);
+ smb_io_rpc_iface ("", &(rpc->transfer), ps, depth);
+}
+
+/*******************************************************************
+creates an RPC_HDR_REQ structure.
+********************************************************************/
+void make_rpc_hdr_req(RPC_HDR_REQ *hdr, uint32 data_len, uint16 opnum)
+{
+ if (hdr == NULL) return;
+
+ hdr->alloc_hint = data_len - 0x18; /* allocation hint */
+ hdr->context_id = 0; /* presentation context identifier */
+ hdr->opnum = opnum; /* opnum */
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_REQ structure.
+********************************************************************/
+void smb_io_rpc_hdr_req(char *desc, RPC_HDR_REQ *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_req");
+ depth++;
+
+ prs_uint32("alloc_hint", ps, depth, &(rpc->alloc_hint));
+ prs_uint16("context_id", ps, depth, &(rpc->context_id));
+ prs_uint16("opnum ", ps, depth, &(rpc->opnum));
+}
+
+/*******************************************************************
+reads or writes an RPC_HDR_RESP structure.
+********************************************************************/
+void smb_io_rpc_hdr_resp(char *desc, RPC_HDR_RESP *rpc, prs_struct *ps, int depth)
+{
+ if (rpc == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_hdr_resp");
+ depth++;
+
+ prs_uint32("alloc_hint", ps, depth, &(rpc->alloc_hint));
+ prs_uint16("context_id", ps, depth, &(rpc->context_id));
+ prs_uint8 ("cancel_ct ", ps, depth, &(rpc->cancel_count));
+ prs_uint8 ("reserved ", ps, depth, &(rpc->reserved));
+}
+
+/*******************************************************************
+creates an RPC_AUTH_NTLMSSP_REQ structure.
+********************************************************************/
+void make_rpc_auth_ntlmssp_req(RPC_AUTH_NTLMSSP_REQ *req,
+ fstring ntlmssp_str, uint32 ntlmssp_ver,
+ uint32 unknown_0, fstring myname, fstring domain)
+{
+ int len_myname = strlen(myname);
+ int len_domain = strlen(domain);
+
+ if (req == NULL) return;
+
+ fstrcpy(req->ntlmssp_str, ntlmssp_str); /* "NTLMSSP" */
+ req->ntlmssp_ver = ntlmssp_ver; /* 0x0000 0001 */
+
+ req->unknown_0 = unknown_0 ; /* 0x00b2b3 */
+ make_str_hdr(&req->hdr_myname, len_myname, len_myname, 1);
+ make_str_hdr(&req->hdr_domain, len_domain, len_domain, 1);
+
+ fstrcpy(req->myname, myname);
+ fstrcpy(req->domain, domain);
+}
+
+/*******************************************************************
+reads or writes an RPC_AUTH_NTLMSSP_REQ structure.
+********************************************************************/
+void smb_io_rpc_auth_ntlmssp_req(char *desc, RPC_AUTH_NTLMSSP_REQ *req, prs_struct *ps, int depth)
+{
+ if (req == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_req");
+ depth++;
+
+ prs_string("ntlmssp_str", ps, depth, req->ntlmssp_str, 0); /* "NTLMSSP" */
+ prs_uint32("ntlmssp_ver", ps, depth, &(req->ntlmssp_ver ));
+
+ prs_uint32("unknown_0 ", ps, depth, &(req->unknown_0 ));
+ smb_io_strhdr("hdr_myname", &(req->hdr_myname), ps, depth);
+ smb_io_strhdr("hdr_domain", &(req->hdr_domain), ps, depth);
+
+ prs_string("myname", ps, depth, req->myname, req->hdr_myname.str_str_len);
+ prs_string("domain", ps, depth, req->domain, req->hdr_domain.str_str_len);
+}
+
+/*******************************************************************
+creates an RPC_AUTH_NTLMSSP_RESP structure.
+********************************************************************/
+void make_rpc_auth_ntlmssp_resp(RPC_AUTH_NTLMSSP_RESP *rsp,
+ uint8 auth_type, uint8 auth_level, uint8 stub_type_len,
+ fstring ntlmssp_str, uint32 ntlmssp_ver,
+ uint32 unknown_1, uint32 unknown_2, uint32 unknown_3,
+ uint8 data[16])
+{
+ if (rsp == NULL) return;
+
+ rsp->auth_type = auth_type; /* nt lm ssp 0x0a */
+ rsp->auth_level = auth_level; /* 0x06 */
+ rsp->stub_type_len = stub_type_len; /* dunno. */
+ rsp->padding = 0; /* padding */
+
+ rsp->ptr_0 = 1; /* non-zero pointer to something */
+
+ fstrcpy(rsp->ntlmssp_str, ntlmssp_str); /* "NTLMSSP" */
+ rsp->ntlmssp_ver = ntlmssp_ver; /* 0x0000 0002 */
+
+ rsp->unknown_1 = unknown_1; /* 0x0000 0000 */
+ rsp->unknown_2 = unknown_2; /* 0x00b2b3 */
+ rsp->unknown_3 = unknown_3; /* 0x0082b1 */
+
+ memcpy(rsp->data, data, sizeof(rsp->data)); /* 0x10 bytes of something, 8 of which are zeros */
+}
+
+/*******************************************************************
+reads or writes an RPC_AUTH_NTLMSSP_RESP structure.
+********************************************************************/
+void smb_io_rpc_auth_ntlmssp_resp(char *desc, RPC_AUTH_NTLMSSP_RESP *rsp, prs_struct *ps, int depth)
+{
+ if (rsp == NULL) return;
+
+ prs_debug(ps, depth, desc, "smb_io_rpc_auth_ntlmssp_resp");
+ depth++;
+
+ prs_uint8("auth_type", ps, depth, &(rsp->auth_type)); /* nt lm ssp 0x0a */
+ prs_uint8("auth_level", ps, depth, &(rsp->auth_level));/* 0x06 */
+ prs_uint8("stub_type_len", ps, depth, &(rsp->stub_type_len));
+ prs_uint8("padding", ps, depth, &(rsp->padding));
+
+ prs_uint32("ptr_0", ps, depth, &(rsp->ptr_0 )); /* non-zero pointer to something */
+
+ prs_string("ntlmssp_str", ps, depth, rsp->ntlmssp_str, 0); /* "NTLMSSP" */
+ prs_uint32("ntlmssp_ver", ps, depth, &(rsp->ntlmssp_ver )); /* 0x0000 0002 */
+
+ prs_uint32("unknown_1", ps, depth, &(rsp->unknown_1)); /* 0x0000 0000 */
+ prs_uint32("unknown_2", ps, depth, &(rsp->unknown_2)); /* 0x00b2b3 */
+ prs_uint32("unknown_3", ps, depth, &(rsp->unknown_3)); /* 0x0082b1 */
+
+ prs_uint8s (False, "data", ps, depth, rsp->data, sizeof(rsp->data));
+}
+
+#if 0
+
+/* attached to the end of encrypted rpc requests and responses */
+/* RPC_AUTH_NTLMSSP_CHK */
+typedef struct rpc_auth_ntlmssp_chk_info
+{
+ uint32 ver; /* 0x1 */
+ uint8 data[12];
+
+} RPC_AUTH_NTLMSSP_CHK;
+
+#endif /* 0 */
+
diff --git a/source/rpc_parse/parse_samr.c b/source/rpc_parse/parse_samr.c
new file mode 100644
index 00000000000..ab07e375f5a
--- /dev/null
+++ b/source/rpc_parse/parse_samr.c
@@ -0,0 +1,2680 @@
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+makes a SAMR_Q_CLOSE_HND structure.
+********************************************************************/
+void make_samr_q_close_hnd(SAMR_Q_CLOSE_HND *q_c, POLICY_HND *hnd)
+{
+ if (q_c == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_samr_q_close_hnd\n"));
+
+ memcpy(&(q_c->pol), hnd, sizeof(q_c->pol));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_close_hnd(char *desc, SAMR_Q_CLOSE_HND *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_close_hnd");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_close_hnd(char *desc, SAMR_R_CLOSE_HND *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_close_hnd");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(r_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_samr_q_open_domain(SAMR_Q_OPEN_DOMAIN *q_u,
+ POLICY_HND *connect_pol, uint32 rid,
+ DOM_SID *sid)
+{
+ if (q_u == NULL) return;
+
+ DEBUG(5,("samr_make_q_open_domain\n"));
+
+ memcpy(&q_u->connect_pol, connect_pol, sizeof(q_u->connect_pol));
+ q_u->rid = rid;
+ make_dom_sid2(&(q_u->dom_sid), sid);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_open_domain(char *desc, SAMR_Q_OPEN_DOMAIN *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_domain");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("connect_pol", &(q_u->connect_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("rid", ps, depth, &(q_u->rid));
+
+ smb_io_dom_sid2("sid", &(q_u->dom_sid), ps, depth);
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_open_domain(char *desc, SAMR_R_OPEN_DOMAIN *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_domain");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("domain_pol", &(r_u->domain_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_samr_q_unknown_3(SAMR_Q_UNKNOWN_3 *q_u,
+ POLICY_HND *user_pol, uint16 switch_value)
+{
+ if (q_u == NULL) return;
+
+ DEBUG(5,("samr_make_q_unknown_3\n"));
+
+ memcpy(&q_u->user_pol, user_pol, sizeof(q_u->user_pol));
+ q_u->switch_value = switch_value;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_unknown_3(char *desc, SAMR_Q_UNKNOWN_3 *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_3");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("user_pol", &(q_u->user_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_value", ps, depth, &(q_u->switch_value));
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_samr_q_unknown_8(SAMR_Q_UNKNOWN_8 *q_u,
+ POLICY_HND *domain_pol, uint16 switch_value)
+{
+ if (q_u == NULL) return;
+
+ DEBUG(5,("samr_make_q_unknown_8\n"));
+
+ memcpy(&q_u->domain_pol, domain_pol, sizeof(q_u->domain_pol));
+ q_u->switch_value = switch_value;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_unknown_8(char *desc, SAMR_Q_UNKNOWN_8 *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_8");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("domain_pol", &(q_u->domain_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_value", ps, depth, &(q_u->switch_value));
+ prs_align(ps);
+}
+/*******************************************************************
+ makes a DOM_SID3 structure.
+
+ calculate length by adding up the size of the components.
+ ********************************************************************/
+void make_dom_sid3(DOM_SID3 *sid3, uint16 unk_0, uint16 unk_1, DOM_SID *sid)
+{
+ if (sid3 == NULL) return;
+
+ sid3->sid = *sid;
+ sid3->len = 2 + 8 + sid3->sid.num_auths * 4;
+}
+
+/*******************************************************************
+reads or writes a SAM_SID3 structure.
+
+this one's odd, because the length (in bytes) is specified at the beginning.
+the length _includes_ the length of the length, too :-)
+
+********************************************************************/
+static void sam_io_dom_sid3(char *desc, DOM_SID3 *sid3, prs_struct *ps, int depth)
+{
+ if (sid3 == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_dom_sid3");
+ depth++;
+
+ prs_uint16("len", ps, depth, &(sid3->len));
+ prs_align(ps);
+ smb_io_dom_sid("", &(sid3->sid), ps, depth);
+}
+
+/*******************************************************************
+makes a SAMR_R_UNKNOWN3 structure.
+
+unknown_2 : 0x0001
+unknown_3 : 0x8004
+
+unknown_4,5 : 0x0000 0014
+
+unknown_6 : 0x0002
+unknown_7 : 0x5800 or 0x0070
+
+********************************************************************/
+static void make_sam_sid_stuff(SAM_SID_STUFF *stf,
+ uint16 unknown_2, uint16 unknown_3,
+ uint32 unknown_4, uint16 unknown_6, uint16 unknown_7,
+ int num_sid3s, DOM_SID3 sid3[MAX_SAM_SIDS])
+{
+ stf->unknown_2 = unknown_2;
+ stf->unknown_3 = unknown_3;
+
+ bzero(stf->padding1, sizeof(stf->padding1));
+
+ stf->unknown_4 = unknown_4;
+ stf->unknown_5 = unknown_4;
+
+ stf->unknown_6 = unknown_6;
+ stf->unknown_7 = unknown_7;
+
+ stf->num_sids = num_sid3s;
+
+ stf->padding2 = 0x0000;
+
+ memcpy(stf->sid, sid3, sizeof(DOM_SID3) * num_sid3s);
+}
+
+/*******************************************************************
+reads or writes a SAM_SID_STUFF structure.
+********************************************************************/
+static void sam_io_sid_stuff(char *desc, SAM_SID_STUFF *stf, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (stf == NULL) return;
+
+ DEBUG(5,("make_sam_sid_stuff\n"));
+
+ prs_uint16("unknown_2", ps, depth, &(stf->unknown_2));
+ prs_uint16("unknown_3", ps, depth, &(stf->unknown_3));
+
+ prs_uint8s(False, "padding1", ps, depth, stf->padding1, sizeof(stf->padding1));
+
+ prs_uint32("unknown_4", ps, depth, &(stf->unknown_4));
+ prs_uint32("unknown_5", ps, depth, &(stf->unknown_5));
+ prs_uint16("unknown_6", ps, depth, &(stf->unknown_6));
+ prs_uint16("unknown_7", ps, depth, &(stf->unknown_7));
+
+ prs_uint32("num_sids ", ps, depth, &(stf->num_sids ));
+ prs_uint16("padding2 ", ps, depth, &(stf->padding2 ));
+
+ SMB_ASSERT_ARRAY(stf->sid, stf->num_sids);
+
+ for (i = 0; i < stf->num_sids; i++)
+ {
+ sam_io_dom_sid3("", &(stf->sid[i]), ps, depth);
+ }
+}
+
+/*******************************************************************
+reads or writes a SAMR_R_UNKNOWN3 structure.
+********************************************************************/
+void make_samr_r_unknown_3(SAMR_R_UNKNOWN_3 *r_u,
+ uint16 unknown_2, uint16 unknown_3,
+ uint32 unknown_4, uint16 unknown_6, uint16 unknown_7,
+ int num_sid3s, DOM_SID3 sid3[MAX_SAM_SIDS],
+ uint32 status)
+{
+ if (r_u == NULL) return;
+
+ DEBUG(5,("samr_make_r_unknown_3\n"));
+
+ r_u->ptr_0 = 0;
+ r_u->ptr_1 = 0;
+
+ if (status == 0x0)
+ {
+ r_u->ptr_0 = 1;
+ r_u->ptr_1 = 1;
+ make_sam_sid_stuff(&(r_u->sid_stuff), unknown_2, unknown_3,
+ unknown_4, unknown_6, unknown_7,
+ num_sid3s, sid3);
+ }
+
+ r_u->status = status;
+}
+
+
+/*******************************************************************
+reads or writes a SAMR_R_UNKNOWN_3 structure.
+
+this one's odd, because the daft buggers use a different mechanism
+for writing out the array of sids. they put the number of sids in
+only one place: they've calculated the length of each sid and jumped
+by that amount. then, retrospectively, the length of the whole buffer
+is put at the beginning of the data stream.
+
+wierd.
+
+********************************************************************/
+void samr_io_r_unknown_3(char *desc, SAMR_R_UNKNOWN_3 *r_u, prs_struct *ps, int depth)
+{
+ int ptr_len0=0;
+ int ptr_len1=0;
+ int ptr_sid_stuff = 0;
+
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_unknown_3");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_0 ", ps, depth, &(r_u->ptr_0 ));
+
+ if (ps->io)
+ {
+ /* reading. do the length later */
+ prs_uint32("sid_stuff_len0", ps, depth, &(r_u->sid_stuff_len0));
+ }
+ else
+ {
+ /* storing */
+ ptr_len0 = ps->offset; ps->offset += 4;
+ }
+
+ if (r_u->ptr_0 != 0)
+ {
+ prs_uint32("ptr_1 ", ps, depth, &(r_u->ptr_1 ));
+ if (ps->io)
+ {
+ /* reading. do the length later */
+ prs_uint32("sid_stuff_len1", ps, depth, &(r_u->sid_stuff_len1));
+ }
+ else
+ {
+ /* storing */
+ ptr_len1 = ps->offset; ps->offset += 4;
+ }
+
+ if (r_u->ptr_1 != 0)
+ {
+ ptr_sid_stuff = ps->offset;
+ sam_io_sid_stuff("", &(r_u->sid_stuff), ps, depth);
+ }
+ }
+
+ if (!(ps->io)) /* storing not reading. do the length, now. */
+ {
+ if (ptr_sid_stuff != 0)
+ {
+ uint32 sid_stuff_len = ps->offset - ptr_sid_stuff;
+ int old_len = ps->offset;
+
+ ps->offset = ptr_len0;
+ prs_uint32("sid_stuff_len0", ps, depth, &sid_stuff_len);
+
+ ps->offset = ptr_len1;
+ prs_uint32("sid_stuff_len1", ps, depth, &sid_stuff_len);
+
+ ps->offset = old_len;
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a SAM_STR1 structure.
+********************************************************************/
+static void 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;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_str1");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("unistr2", &(sam->uni_acct_name), acct_buf, ps, depth); /* account name unicode string */
+ smb_io_unistr2("unistr2", &(sam->uni_full_name), name_buf, ps, depth); /* full name unicode string */
+ smb_io_unistr2("unistr2", &(sam->uni_acct_desc), desc_buf, ps, depth); /* account description unicode string */
+}
+
+/*******************************************************************
+makes a SAM_ENTRY1 structure.
+********************************************************************/
+static void make_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)
+{
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_entry1\n"));
+
+ sam->user_idx = user_idx;
+ sam->rid_user = rid_user;
+ sam->acb_info = acb_info;
+ sam->pad = 0;
+
+ make_uni_hdr(&(sam->hdr_acct_name), len_sam_name, len_sam_name, len_sam_name != 0);
+ make_uni_hdr(&(sam->hdr_user_name), len_sam_full, len_sam_full, len_sam_full != 0);
+ make_uni_hdr(&(sam->hdr_user_desc), len_sam_desc, len_sam_desc, len_sam_desc != 0);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY1 structure.
+********************************************************************/
+static void sam_io_sam_entry1(char *desc, SAM_ENTRY1 *sam, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("user_idx ", ps, depth, &(sam->user_idx ));
+
+ prs_uint32("rid_user ", ps, depth, &(sam->rid_user ));
+ prs_uint16("acb_info ", ps, depth, &(sam->acb_info ));
+ prs_uint16("pad ", ps, depth, &(sam->pad ));
+
+ smb_io_unihdr("unihdr", &(sam->hdr_acct_name), ps, depth); /* account name unicode string header */
+ smb_io_unihdr("unihdr", &(sam->hdr_user_name), ps, depth); /* account name unicode string header */
+ smb_io_unihdr("unihdr", &(sam->hdr_user_desc), ps, depth); /* account name unicode string header */
+}
+
+/*******************************************************************
+reads or writes a SAM_STR2 structure.
+********************************************************************/
+static void sam_io_sam_str2(char *desc, SAM_STR2 *sam, uint32 acct_buf, uint32 desc_buf, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_str2");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("unistr2", &(sam->uni_srv_name), acct_buf, ps, depth); /* account name unicode string */
+ smb_io_unistr2("unistr2", &(sam->uni_srv_desc), desc_buf, ps, depth); /* account description unicode string */
+}
+
+/*******************************************************************
+makes a SAM_ENTRY2 structure.
+********************************************************************/
+static void make_sam_entry2(SAM_ENTRY2 *sam, uint32 user_idx,
+ uint32 len_sam_name, uint32 len_sam_desc,
+ uint32 rid_user, uint16 acb_info)
+{
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_entry2\n"));
+
+ sam->user_idx = user_idx;
+ sam->rid_user = rid_user;
+ sam->acb_info = acb_info;
+ sam->pad = 0;
+
+ make_uni_hdr(&(sam->hdr_srv_name), len_sam_name, len_sam_name, len_sam_name != 0);
+ make_uni_hdr(&(sam->hdr_srv_desc), len_sam_desc, len_sam_desc, len_sam_desc != 0);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY2 structure.
+********************************************************************/
+static void sam_io_sam_entry2(char *desc, SAM_ENTRY2 *sam, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("user_idx ", ps, depth, &(sam->user_idx ));
+
+ prs_uint32("rid_user ", ps, depth, &(sam->rid_user ));
+ prs_uint16("acb_info ", ps, depth, &(sam->acb_info ));
+ prs_uint16("pad ", ps, depth, &(sam->pad ));
+
+ smb_io_unihdr("unihdr", &(sam->hdr_srv_name), ps, depth); /* account name unicode string header */
+ smb_io_unihdr("unihdr", &(sam->hdr_srv_desc), ps, depth); /* account name unicode string header */
+}
+
+/*******************************************************************
+reads or writes a SAM_STR3 structure.
+********************************************************************/
+static void sam_io_sam_str3(char *desc, SAM_STR3 *sam, uint32 acct_buf, uint32 desc_buf, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_str3");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("unistr2", &(sam->uni_grp_name), acct_buf, ps, depth); /* account name unicode string */
+ smb_io_unistr2("unistr2", &(sam->uni_grp_desc), desc_buf, ps, depth); /* account description unicode string */
+}
+
+/*******************************************************************
+makes a SAM_ENTRY3 structure.
+********************************************************************/
+static void make_sam_entry3(SAM_ENTRY3 *sam, uint32 grp_idx,
+ uint32 len_grp_name, uint32 len_grp_desc, uint32 rid_grp)
+{
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_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 */
+
+ make_uni_hdr(&(sam->hdr_grp_name), len_grp_name, len_grp_name, len_grp_name != 0);
+ make_uni_hdr(&(sam->hdr_grp_desc), len_grp_desc, len_grp_desc, len_grp_desc != 0);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY3 structure.
+********************************************************************/
+static void sam_io_sam_entry3(char *desc, SAM_ENTRY3 *sam, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry3");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("grp_idx", ps, depth, &(sam->grp_idx));
+
+ prs_uint32("rid_grp", ps, depth, &(sam->rid_grp));
+ prs_uint32("attr ", ps, depth, &(sam->attr ));
+
+ smb_io_unihdr("unihdr", &(sam->hdr_grp_name), ps, depth); /* account name unicode string header */
+ smb_io_unihdr("unihdr", &(sam->hdr_grp_desc), ps, depth); /* account name unicode string header */
+}
+
+/*******************************************************************
+makes a SAM_ENTRY structure.
+********************************************************************/
+static void make_sam_entry(SAM_ENTRY *sam, uint32 len_sam_name, uint32 rid)
+{
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_entry\n"));
+
+ sam->rid = rid;
+ make_uni_hdr(&(sam->hdr_name), len_sam_name, len_sam_name, len_sam_name != 0);
+}
+
+/*******************************************************************
+reads or writes a SAM_ENTRY structure.
+********************************************************************/
+static void sam_io_sam_entry(char *desc, SAM_ENTRY *sam, prs_struct *ps, int depth)
+{
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_entry");
+ depth++;
+
+ prs_align(ps);
+ prs_uint32("rid", ps, depth, &(sam->rid ));
+ smb_io_unihdr("unihdr", &(sam->hdr_name), ps, depth); /* account name unicode string header */
+}
+
+
+/*******************************************************************
+makes a SAMR_Q_ENUM_DOM_USERS structure.
+********************************************************************/
+void make_samr_q_enum_dom_users(SAMR_Q_ENUM_DOM_USERS *q_e, POLICY_HND *pol,
+ uint16 req_num_entries, uint16 unk_0,
+ uint16 acb_mask, uint16 unk_1, uint32 size)
+{
+ if (q_e == NULL || pol == NULL) return;
+
+ DEBUG(5,("make_q_enum_dom_users\n"));
+
+ memcpy(&(q_e->pol), pol, sizeof(*pol));
+
+ q_e->req_num_entries = req_num_entries; /* zero indicates lots */
+ q_e->unknown_0 = unk_0; /* this gets returned in the response */
+ q_e->acb_mask = acb_mask;
+ q_e->unknown_1 = unk_1;
+ q_e->max_size = size;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_dom_users");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_e->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("req_num_entries", ps, depth, &(q_e->req_num_entries));
+ prs_uint16("unknown_0 ", ps, depth, &(q_e->unknown_0 ));
+
+ prs_uint16("acb_mask ", ps, depth, &(q_e->acb_mask ));
+ prs_uint16("unknown_1 ", ps, depth, &(q_e->unknown_1 ));
+
+ prs_uint32("max_size ", ps, depth, &(q_e->max_size ));
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAMR_R_ENUM_DOM_USERS structure.
+********************************************************************/
+void make_samr_r_enum_dom_users(SAMR_R_ENUM_DOM_USERS *r_u,
+ uint16 total_num_entries, uint16 unk_0,
+ uint32 num_sam_entries, SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES], uint32 status)
+{
+ int i;
+
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_enum_dom_users\n"));
+
+ if (num_sam_entries >= MAX_SAM_ENTRIES)
+ {
+ num_sam_entries = MAX_SAM_ENTRIES;
+ DEBUG(5,("limiting number of entries to %d\n",
+ num_sam_entries));
+ }
+
+ r_u->total_num_entries = total_num_entries;
+ r_u->unknown_0 = unk_0;
+
+ if (total_num_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;
+
+ SMB_ASSERT_ARRAY(r_u->sam, num_sam_entries);
+ SMB_ASSERT_ARRAY(r_u->uni_acct_name, num_sam_entries);
+
+ for (i = 0; i < num_sam_entries; i++)
+ {
+ make_sam_entry(&(r_u->sam[i]),
+ pass[i].uni_user_name.uni_str_len,
+ pass[i].user_rid);
+
+ copy_unistr2(&(r_u->uni_acct_name[i]), &(pass[i].uni_user_name));
+ }
+
+ 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;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_enum_dom_users(char *desc, SAMR_R_ENUM_DOM_USERS *r_u, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_dom_users");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint16("total_num_entries", ps, depth, &(r_u->total_num_entries));
+ prs_uint16("unknown_0 ", ps, depth, &(r_u->unknown_0 ));
+ prs_uint32("ptr_entries1", ps, depth, &(r_u->ptr_entries1));
+
+ if (r_u->total_num_entries != 0 && r_u->ptr_entries1 != 0)
+ {
+ prs_uint32("num_entries2", ps, depth, &(r_u->num_entries2));
+ prs_uint32("ptr_entries2", ps, depth, &(r_u->ptr_entries2));
+ prs_uint32("num_entries3", ps, depth, &(r_u->num_entries3));
+
+ SMB_ASSERT_ARRAY(r_u->sam, r_u->num_entries2);
+
+ for (i = 0; i < r_u->num_entries2; i++)
+ {
+ prs_grow(ps);
+ sam_io_sam_entry("", &(r_u->sam[i]), ps, depth);
+ }
+
+ SMB_ASSERT_ARRAY(r_u->uni_acct_name, r_u->num_entries2);
+
+ for (i = 0; i < r_u->num_entries2; i++)
+ {
+ prs_grow(ps);
+ smb_io_unistr2("", &(r_u->uni_acct_name[i]), r_u->sam[i].hdr_name.buffer, ps, depth);
+ }
+
+ prs_align(ps);
+
+ prs_uint32("num_entries4", ps, depth, &(r_u->num_entries4));
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+makes a SAMR_Q_ENUM_DOM_ALIASES structure.
+********************************************************************/
+void make_samr_q_enum_dom_aliases(SAMR_Q_ENUM_DOM_ALIASES *q_e, POLICY_HND *pol, uint32 size)
+{
+ if (q_e == NULL || pol == NULL) return;
+
+ DEBUG(5,("make_q_enum_dom_aliases\n"));
+
+ memcpy(&(q_e->pol), pol, sizeof(*pol));
+
+ q_e->unknown_0 = 0;
+ q_e->max_size = size;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_dom_aliases");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_e->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("unknown_0", ps, depth, &(q_e->unknown_0));
+ prs_uint32("max_size ", ps, depth, &(q_e->max_size ));
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAMR_R_ENUM_DOM_ALIASES structure.
+********************************************************************/
+void make_samr_r_enum_dom_aliases(SAMR_R_ENUM_DOM_ALIASES *r_u,
+ uint32 num_sam_entries, SAM_USER_INFO_21 grps[MAX_SAM_ENTRIES],
+ uint32 status)
+{
+ int i;
+
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_enum_dom_aliases\n"));
+
+ if (num_sam_entries >= MAX_SAM_ENTRIES)
+ {
+ num_sam_entries = MAX_SAM_ENTRIES;
+ DEBUG(5,("limiting number of entries to %d\n",
+ num_sam_entries));
+ }
+
+ r_u->num_entries = num_sam_entries;
+
+ if (num_sam_entries > 0)
+ {
+ r_u->ptr_entries = 1;
+ r_u->num_entries2 = num_sam_entries;
+ r_u->ptr_entries2 = 1;
+ r_u->num_entries3 = num_sam_entries;
+
+ SMB_ASSERT_ARRAY(r_u->sam, num_sam_entries);
+
+ for (i = 0; i < num_sam_entries; i++)
+ {
+ make_sam_entry(&(r_u->sam[i]),
+ grps[i].uni_user_name.uni_str_len,
+ grps[i].user_rid);
+
+ copy_unistr2(&(r_u->uni_grp_name[i]), &(grps[i].uni_user_name));
+ }
+
+ r_u->num_entries4 = num_sam_entries;
+ }
+ else
+ {
+ r_u->ptr_entries = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_enum_dom_aliases(char *desc, SAMR_R_ENUM_DOM_ALIASES *r_u, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_dom_aliases");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries", ps, depth, &(r_u->num_entries));
+ prs_uint32("ptr_entries", ps, depth, &(r_u->ptr_entries));
+
+ if (r_u->num_entries != 0 && r_u->ptr_entries != 0)
+ {
+ prs_uint32("num_entries2", ps, depth, &(r_u->num_entries2));
+ prs_uint32("ptr_entries2", ps, depth, &(r_u->ptr_entries2));
+ prs_uint32("num_entries3", ps, depth, &(r_u->num_entries3));
+
+ SMB_ASSERT_ARRAY(r_u->sam, r_u->num_entries);
+
+ for (i = 0; i < r_u->num_entries; i++)
+ {
+ sam_io_sam_entry("", &(r_u->sam[i]), ps, depth);
+ }
+
+ for (i = 0; i < r_u->num_entries; i++)
+ {
+ smb_io_unistr2("", &(r_u->uni_grp_name[i]), r_u->sam[i].hdr_name.buffer, ps, depth);
+ }
+
+ prs_align(ps);
+
+ prs_uint32("num_entries4", ps, depth, &(r_u->num_entries4));
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+/*******************************************************************
+makes a SAMR_Q_QUERY_DISPINFO structure.
+********************************************************************/
+void make_samr_q_query_dispinfo(SAMR_Q_QUERY_DISPINFO *q_e, POLICY_HND *pol,
+ uint16 switch_level, uint32 start_idx, uint32 size)
+{
+ if (q_e == NULL || pol == NULL) return;
+
+ DEBUG(5,("make_q_query_dispinfo\n"));
+
+ memcpy(&(q_e->pol), pol, sizeof(*pol));
+
+ q_e->switch_level = switch_level;
+
+ q_e->unknown_0 = 0;
+ q_e->start_idx = start_idx;
+ q_e->unknown_1 = 0x000007d0;
+ q_e->max_size = size;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_query_dispinfo(char *desc, SAMR_Q_QUERY_DISPINFO *q_e, prs_struct *ps, int depth)
+{
+ if (q_e == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_dispinfo");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_e->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_level", ps, depth, &(q_e->switch_level));
+ prs_uint16("unknown_0 ", ps, depth, &(q_e->unknown_0 ));
+ prs_uint32("start_idx ", ps, depth, &(q_e->start_idx ));
+ prs_uint32("unknown_1 ", ps, depth, &(q_e->unknown_1 ));
+ prs_uint32("max_size ", ps, depth, &(q_e->max_size ));
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAM_INFO_2 structure.
+********************************************************************/
+void make_sam_info_2(SAM_INFO_2 *sam, uint32 acb_mask,
+ uint32 start_idx, uint32 num_sam_entries,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+{
+ int i;
+ int entries_added;
+
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_info_2\n"));
+
+ if (num_sam_entries >= MAX_SAM_ENTRIES)
+ {
+ num_sam_entries = MAX_SAM_ENTRIES;
+ DEBUG(5,("limiting number of entries to %d\n",
+ num_sam_entries));
+ }
+
+ for (i = start_idx, entries_added = 0; i < num_sam_entries; i++)
+ {
+ if (IS_BITS_SET_ALL(pass[i].acb_info, acb_mask))
+ {
+ make_sam_entry2(&(sam->sam[entries_added]),
+ start_idx + entries_added + 1,
+ pass[i].uni_user_name.uni_str_len,
+ pass[i].uni_acct_desc.uni_str_len,
+ pass[i].user_rid,
+ pass[i].acb_info);
+
+ copy_unistr2(&(sam->str[entries_added].uni_srv_name), &(pass[i].uni_user_name));
+ copy_unistr2(&(sam->str[entries_added].uni_srv_desc), &(pass[i].uni_acct_desc));
+
+ entries_added++;
+ }
+
+ sam->num_entries = entries_added;
+ sam->ptr_entries = 1;
+ sam->num_entries2 = entries_added;
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void sam_io_sam_info_2(char *desc, SAM_INFO_2 *sam, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_info_2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries ", ps, depth, &(sam->num_entries ));
+ prs_uint32("ptr_entries ", ps, depth, &(sam->ptr_entries ));
+
+ prs_uint32("num_entries2 ", ps, depth, &(sam->num_entries2 ));
+
+ SMB_ASSERT_ARRAY(sam->sam, sam->num_entries);
+
+ for (i = 0; i < sam->num_entries; i++)
+ {
+ sam_io_sam_entry2("", &(sam->sam[i]), ps, depth);
+ }
+
+ for (i = 0; i < sam->num_entries; i++)
+ {
+ sam_io_sam_str2 ("", &(sam->str[i]),
+ sam->sam[i].hdr_srv_name.buffer,
+ sam->sam[i].hdr_srv_desc.buffer,
+ ps, depth);
+ }
+}
+
+
+/*******************************************************************
+makes a SAM_INFO_1 structure.
+********************************************************************/
+void make_sam_info_1(SAM_INFO_1 *sam, uint32 acb_mask,
+ uint32 start_idx, uint32 num_sam_entries,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+{
+ int i;
+ int entries_added;
+
+ if (sam == NULL) return;
+
+ DEBUG(5,("make_sam_info_1\n"));
+
+ if (num_sam_entries >= MAX_SAM_ENTRIES)
+ {
+ num_sam_entries = MAX_SAM_ENTRIES;
+ DEBUG(5,("limiting number of entries to %d\n",
+ num_sam_entries));
+ }
+
+ for (i = start_idx, entries_added = 0; i < num_sam_entries; i++)
+ {
+ if (IS_BITS_SET_ALL(pass[i].acb_info, acb_mask))
+ {
+ make_sam_entry1(&(sam->sam[entries_added]),
+ start_idx + entries_added + 1,
+ pass[i].uni_user_name.uni_str_len,
+ pass[i].uni_full_name.uni_str_len,
+ pass[i].uni_acct_desc.uni_str_len,
+ pass[i].user_rid,
+ pass[i].acb_info);
+
+ copy_unistr2(&(sam->str[entries_added].uni_acct_name), &(pass[i].uni_user_name));
+ copy_unistr2(&(sam->str[entries_added].uni_full_name), &(pass[i].uni_full_name));
+ copy_unistr2(&(sam->str[entries_added].uni_acct_desc), &(pass[i].uni_acct_desc));
+
+ entries_added++;
+ }
+ }
+
+ sam->num_entries = entries_added;
+ sam->ptr_entries = 1;
+ sam->num_entries2 = entries_added;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void sam_io_sam_info_1(char *desc, SAM_INFO_1 *sam, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (sam == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_sam_info_1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries ", ps, depth, &(sam->num_entries ));
+ prs_uint32("ptr_entries ", ps, depth, &(sam->ptr_entries ));
+
+ prs_uint32("num_entries2 ", ps, depth, &(sam->num_entries2 ));
+
+ SMB_ASSERT_ARRAY(sam->sam, sam->num_entries);
+
+ for (i = 0; i < sam->num_entries; i++)
+ {
+ sam_io_sam_entry1("", &(sam->sam[i]), ps, depth);
+ }
+
+ for (i = 0; i < sam->num_entries; i++)
+ {
+ 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);
+ }
+}
+
+
+/*******************************************************************
+makes a SAMR_R_QUERY_DISPINFO structure.
+********************************************************************/
+void make_samr_r_query_dispinfo(SAMR_R_QUERY_DISPINFO *r_u,
+ uint16 switch_level, SAM_INFO_CTR *ctr, uint32 status)
+{
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_query_dispinfo\n"));
+
+ if (status == 0x0)
+ {
+ r_u->unknown_0 = 0x0000001;
+ r_u->unknown_1 = 0x0000001;
+ }
+ else
+ {
+ r_u->unknown_0 = 0x0;
+ r_u->unknown_1 = 0x0;
+ }
+
+ r_u->switch_level = switch_level;
+ r_u->ctr = ctr;
+ r_u->status = status;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_query_dispinfo(char *desc, SAMR_R_QUERY_DISPINFO *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_dispinfo");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("unknown_0 ", ps, depth, &(r_u->unknown_0 ));
+ prs_uint32("unknown_1 ", ps, depth, &(r_u->unknown_1 ));
+ prs_uint16("switch_level ", ps, depth, &(r_u->switch_level ));
+
+ prs_align(ps);
+
+ switch (r_u->switch_level)
+ {
+ case 0x1:
+ {
+ sam_io_sam_info_1("users", r_u->ctr->sam.info1, ps, depth);
+ break;
+ }
+ case 0x2:
+ {
+ sam_io_sam_info_2("servers", r_u->ctr->sam.info2, ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("samr_io_r_query_dispinfo: unknown switch value\n"));
+ break;
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+/*******************************************************************
+makes a SAMR_Q_ENUM_DOM_GROUPS structure.
+********************************************************************/
+void make_samr_q_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_e, POLICY_HND *pol,
+ uint16 switch_level, uint32 start_idx, uint32 size)
+{
+ if (q_e == NULL || pol == NULL) return;
+
+ DEBUG(5,("make_q_enum_dom_groups\n"));
+
+ memcpy(&(q_e->pol), pol, sizeof(*pol));
+
+ q_e->switch_level = switch_level;
+
+ q_e->unknown_0 = 0;
+ q_e->start_idx = start_idx;
+ q_e->unknown_1 = 0x000007d0;
+ q_e->max_size = size;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "samr_io_q_enum_dom_groups");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_e->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_level", ps, depth, &(q_e->switch_level));
+ prs_uint16("unknown_0 ", ps, depth, &(q_e->unknown_0 ));
+ prs_uint32("start_idx ", ps, depth, &(q_e->start_idx ));
+ prs_uint32("unknown_1 ", ps, depth, &(q_e->unknown_1 ));
+ prs_uint32("max_size ", ps, depth, &(q_e->max_size ));
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAMR_R_ENUM_DOM_GROUPS structure.
+********************************************************************/
+void make_samr_r_enum_dom_groups(SAMR_R_ENUM_DOM_GROUPS *r_u,
+ uint32 start_idx, uint32 num_sam_entries,
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES],
+ uint32 status)
+{
+ int i;
+ int entries_added;
+
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_enum_dom_groups\n"));
+
+ if (num_sam_entries >= MAX_SAM_ENTRIES)
+ {
+ num_sam_entries = MAX_SAM_ENTRIES;
+ DEBUG(5,("limiting number of entries to %d\n",
+ num_sam_entries));
+ }
+
+ if (status == 0x0)
+ {
+ for (i = start_idx, entries_added = 0; i < num_sam_entries; i++)
+ {
+ make_sam_entry3(&(r_u->sam[entries_added]),
+ start_idx + entries_added + 1,
+ pass[i].uni_user_name.uni_str_len,
+ pass[i].uni_acct_desc.uni_str_len,
+ pass[i].user_rid);
+
+ copy_unistr2(&(r_u->str[entries_added].uni_grp_name), &(pass[i].uni_user_name));
+ copy_unistr2(&(r_u->str[entries_added].uni_grp_desc), &(pass[i].uni_acct_desc));
+
+ entries_added++;
+ }
+
+ if (entries_added > 0)
+ {
+ r_u->unknown_0 = 0x0000492;
+ r_u->unknown_1 = 0x000049a;
+ }
+ else
+ {
+ r_u->unknown_0 = 0x0;
+ r_u->unknown_1 = 0x0;
+ }
+ r_u->switch_level = 3;
+ r_u->num_entries = entries_added;
+ r_u->ptr_entries = 1;
+ r_u->num_entries2 = entries_added;
+ }
+ else
+ {
+ r_u->switch_level = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_enum_dom_groups(char *desc, SAMR_R_ENUM_DOM_GROUPS *r_u, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_enum_dom_groups");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("unknown_0 ", ps, depth, &(r_u->unknown_0 ));
+ prs_uint32("unknown_1 ", ps, depth, &(r_u->unknown_1 ));
+ prs_uint32("switch_level ", ps, depth, &(r_u->switch_level ));
+
+ if (r_u->switch_level != 0)
+ {
+ prs_uint32("num_entries ", ps, depth, &(r_u->num_entries ));
+ prs_uint32("ptr_entries ", ps, depth, &(r_u->ptr_entries ));
+
+ prs_uint32("num_entries2 ", ps, depth, &(r_u->num_entries2 ));
+
+ SMB_ASSERT_ARRAY(r_u->sam, r_u->num_entries);
+
+ for (i = 0; i < r_u->num_entries; i++)
+ {
+ sam_io_sam_entry3("", &(r_u->sam[i]), ps, depth);
+ }
+
+ for (i = 0; i < r_u->num_entries; i++)
+ {
+ sam_io_sam_str3 ("", &(r_u->str[i]),
+ r_u->sam[i].hdr_grp_name.buffer,
+ r_u->sam[i].hdr_grp_desc.buffer,
+ ps, depth);
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+/*******************************************************************
+makes a SAMR_Q_QUERY_ALIASINFO structure.
+********************************************************************/
+void make_samr_q_query_aliasinfo(SAMR_Q_QUERY_ALIASINFO *q_e,
+ POLICY_HND *pol,
+ uint16 switch_level)
+{
+ if (q_e == NULL || pol == NULL) return;
+
+ DEBUG(5,("make_q_query_aliasinfo\n"));
+
+ memcpy(&(q_e->pol), pol, sizeof(*pol));
+
+ q_e->switch_level = switch_level;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_query_aliasinfo(char *desc, SAMR_Q_QUERY_ALIASINFO *q_e, prs_struct *ps, int depth)
+{
+ if (q_e == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_aliasinfo");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_e->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_level", ps, depth, &(q_e->switch_level));
+}
+
+
+/*******************************************************************
+makes a SAMR_R_QUERY_ALIASINFO structure.
+********************************************************************/
+void make_samr_r_query_aliasinfo(SAMR_R_QUERY_ALIASINFO *r_u,
+ uint16 switch_value, char *acct_desc,
+ uint32 status)
+{
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_query_aliasinfo\n"));
+
+ r_u->ptr = 0;
+
+ if (status == 0)
+ {
+ r_u->switch_value = switch_value;
+
+ switch (switch_value)
+ {
+ case 3:
+ {
+ int acct_len = acct_desc ? strlen(acct_desc) : 0;
+
+ r_u->ptr = 1;
+
+ make_uni_hdr(&(r_u->alias.info3.hdr_acct_desc), acct_len , acct_len, acct_desc ? 1 : 0);
+ make_unistr2(&(r_u->alias.info3.uni_acct_desc), acct_desc, acct_len);
+
+ break;
+ }
+
+ default:
+ {
+ DEBUG(4,("make_samr_r_query_aliasinfo: unsupported switch level\n"));
+ break;
+ }
+ }
+ }
+
+ r_u->status = status;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_query_aliasinfo(char *desc, SAMR_R_QUERY_ALIASINFO *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_aliasinfo");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr ", ps, depth, &(r_u->ptr ));
+
+ if (r_u->ptr != 0)
+ {
+ prs_uint16("switch_value", ps, depth, &(r_u->switch_value));
+ prs_align(ps);
+
+ if (r_u->switch_value != 0)
+ {
+ switch (r_u->switch_value)
+ {
+ case 3:
+ {
+ smb_io_unihdr ("", &(r_u->alias.info3.hdr_acct_desc), ps, depth);
+ smb_io_unistr2("", &(r_u->alias.info3.uni_acct_desc), r_u->alias.info3.hdr_acct_desc.buffer, ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(4,("samr_io_r_query_aliasinfo: unsupported switch level\n"));
+ break;
+ }
+ }
+ }
+ }
+
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a SAMR_Q_LOOKUP_IDS structure.
+********************************************************************/
+void samr_io_q_lookup_ids(char *desc, SAMR_Q_LOOKUP_IDS *q_u, prs_struct *ps, int depth)
+{
+ fstring tmp;
+ int i;
+
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_lookup_ids");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("num_sids1", ps, depth, &(q_u->num_sids1));
+ prs_uint32("ptr ", ps, depth, &(q_u->ptr ));
+ prs_uint32("num_sids2", ps, depth, &(q_u->num_sids2));
+
+ SMB_ASSERT_ARRAY(q_u->ptr_sid, q_u->num_sids2);
+
+ for (i = 0; i < q_u->num_sids2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "ptr[%02d]", i);
+ prs_uint32(tmp, ps, depth, &(q_u->ptr_sid[i]));
+ }
+
+ for (i = 0; i < q_u->num_sids2; i++)
+ {
+ if (q_u->ptr_sid[i] != 0)
+ {
+ slprintf(tmp, sizeof(tmp)-1, "sid[%02d]", i);
+ smb_io_dom_sid2(tmp, &(q_u->sid[i]), ps, depth);
+ }
+ }
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAMR_R_LOOKUP_IDS structure.
+********************************************************************/
+void make_samr_r_lookup_ids(SAMR_R_LOOKUP_IDS *r_u,
+ uint32 num_rids, uint32 *rid, uint32 status)
+{
+ int i;
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_lookup_ids\n"));
+
+ if (status == 0x0)
+ {
+ r_u->num_entries = num_rids;
+ r_u->ptr = 1;
+ r_u->num_entries2 = num_rids;
+
+ SMB_ASSERT_ARRAY(r_u->rid, num_rids);
+
+ for (i = 0; i < num_rids; i++)
+ {
+ r_u->rid[i] = rid[i];
+ }
+ }
+ else
+ {
+ r_u->num_entries = 0;
+ r_u->ptr = 0;
+ r_u->num_entries2 = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_lookup_ids(char *desc, SAMR_R_LOOKUP_IDS *r_u, prs_struct *ps, int depth)
+{
+ fstring tmp;
+ int i;
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_lookup_ids");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries", ps, depth, &(r_u->num_entries));
+ prs_uint32("ptr ", ps, depth, &(r_u->ptr ));
+ prs_uint32("num_entries2", ps, depth, &(r_u->num_entries2));
+
+ if (r_u->num_entries != 0)
+ {
+ SMB_ASSERT_ARRAY(r_u->rid, r_u->num_entries2);
+
+ for (i = 0; i < r_u->num_entries2; i++)
+ {
+ slprintf(tmp, sizeof(tmp)-1, "rid[%02d]", i);
+ prs_uint32(tmp, ps, depth, &(r_u->rid[i]));
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_lookup_names(char *desc, SAMR_Q_LOOKUP_NAMES *q_u, prs_struct *ps, int depth)
+{
+ int i;
+
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_lookup_names");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("num_rids1", ps, depth, &(q_u->num_rids1));
+ prs_uint32("rid ", ps, depth, &(q_u->rid ));
+ prs_uint32("ptr ", ps, depth, &(q_u->ptr ));
+ prs_uint32("num_rids2", ps, depth, &(q_u->num_rids2));
+
+ SMB_ASSERT_ARRAY(q_u->hdr_user_name, q_u->num_rids2);
+
+ for (i = 0; i < q_u->num_rids2; i++)
+ {
+ smb_io_unihdr ("", &(q_u->hdr_user_name[i]), ps, depth);
+ }
+ for (i = 0; i < q_u->num_rids2; i++)
+ {
+ smb_io_unistr2("", &(q_u->uni_user_name[i]), q_u->hdr_user_name[i].buffer, ps, depth);
+ }
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAMR_R_LOOKUP_NAMES structure.
+********************************************************************/
+void make_samr_r_lookup_names(SAMR_R_LOOKUP_NAMES *r_u,
+ uint32 num_rids, uint32 *rid, uint32 status)
+{
+ int i;
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_lookup_names\n"));
+
+ if (status == 0x0)
+ {
+ r_u->num_entries = num_rids;
+ r_u->undoc_buffer = 1;
+ r_u->num_entries2 = num_rids;
+
+ SMB_ASSERT_ARRAY(r_u->dom_rid, num_rids);
+
+ for (i = 0; i < num_rids; i++)
+ {
+ make_dom_rid3(&(r_u->dom_rid[i]), rid[i]);
+ }
+
+ r_u->num_entries3 = num_rids;
+ }
+ else
+ {
+ r_u->num_entries = 0;
+ r_u->undoc_buffer = 0;
+ r_u->num_entries2 = 0;
+ r_u->num_entries3 = 0;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_lookup_names(char *desc, SAMR_R_LOOKUP_NAMES *r_u, prs_struct *ps, int depth)
+{
+ int i;
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_lookup_names");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries ", ps, depth, &(r_u->num_entries ));
+ prs_uint32("undoc_buffer", ps, depth, &(r_u->undoc_buffer));
+ prs_uint32("num_entries2", ps, depth, &(r_u->num_entries2));
+
+ if (r_u->num_entries != 0)
+ {
+ SMB_ASSERT_ARRAY(r_u->dom_rid, r_u->num_entries2);
+
+ for (i = 0; i < r_u->num_entries2; i++)
+ {
+ smb_io_dom_rid3("", &(r_u->dom_rid[i]), ps, depth);
+ }
+
+ }
+
+ prs_uint32("num_entries3", ps, depth, &(r_u->num_entries3));
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_unknown_12(char *desc, SAMR_Q_UNKNOWN_12 *q_u, prs_struct *ps, int depth)
+{
+ int i;
+ fstring tmp;
+
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_12");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("num_gids1", ps, depth, &(q_u->num_gids1));
+ prs_uint32("rid ", ps, depth, &(q_u->rid ));
+ prs_uint32("ptr ", ps, depth, &(q_u->ptr ));
+ prs_uint32("num_gids2", ps, depth, &(q_u->num_gids2));
+
+ SMB_ASSERT_ARRAY(q_u->gid, q_u->num_gids2);
+
+ for (i = 0; i < q_u->num_gids2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "gid[%02d] ", i);
+ prs_uint32(tmp, ps, depth, &(q_u->gid[i]));
+ }
+
+ prs_align(ps);
+}
+
+
+/*******************************************************************
+makes a SAMR_R_UNKNOWN_12 structure.
+********************************************************************/
+void make_samr_r_unknown_12(SAMR_R_UNKNOWN_12 *r_u,
+ uint32 num_aliases, fstring *als_name, uint32 *num_als_usrs,
+ uint32 status)
+{
+ int i;
+ if (r_u == NULL || als_name == NULL || num_als_usrs == NULL) return;
+
+ DEBUG(5,("make_samr_r_unknown_12\n"));
+
+ if (status == 0x0)
+ {
+ r_u->num_aliases1 = num_aliases;
+ r_u->ptr_aliases = 1;
+ r_u->num_aliases2 = num_aliases;
+
+ r_u->num_als_usrs1 = num_aliases;
+ r_u->ptr_als_usrs = 1;
+ r_u->num_als_usrs2 = num_aliases;
+
+ SMB_ASSERT_ARRAY(r_u->hdr_als_name, num_aliases);
+
+ for (i = 0; i < num_aliases; i++)
+ {
+ int als_len = als_name[i] != NULL ? strlen(als_name[i]) : 0;
+ make_uni_hdr(&(r_u->hdr_als_name[i]), als_len , als_len, als_name[i] ? 1 : 0);
+ make_unistr2(&(r_u->uni_als_name[i]), als_name[i], als_len);
+ r_u->num_als_usrs[i] = num_als_usrs[i];
+ }
+ }
+ else
+ {
+ r_u->num_aliases1 = num_aliases;
+ r_u->ptr_aliases = 0;
+ r_u->num_aliases2 = num_aliases;
+
+ r_u->num_als_usrs1 = num_aliases;
+ r_u->ptr_als_usrs = 0;
+ r_u->num_als_usrs2 = num_aliases;
+ }
+
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_unknown_12(char *desc, SAMR_R_UNKNOWN_12 *r_u, prs_struct *ps, int depth)
+{
+ int i;
+ fstring tmp;
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_unknown_12");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_aliases1", ps, depth, &(r_u->num_aliases1));
+ prs_uint32("ptr_aliases ", ps, depth, &(r_u->ptr_aliases ));
+ prs_uint32("num_aliases2", ps, depth, &(r_u->num_aliases2));
+
+ if (r_u->ptr_aliases != 0 && r_u->num_aliases1 != 0)
+ {
+ SMB_ASSERT_ARRAY(r_u->hdr_als_name, r_u->num_aliases2);
+
+ for (i = 0; i < r_u->num_aliases2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "als_hdr[%02d] ", i);
+ smb_io_unihdr ("", &(r_u->hdr_als_name[i]), ps, depth);
+ }
+ for (i = 0; i < r_u->num_aliases2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "als_str[%02d] ", i);
+ smb_io_unistr2("", &(r_u->uni_als_name[i]), r_u->hdr_als_name[i].buffer, ps, depth);
+ }
+ }
+
+ prs_align(ps);
+
+ prs_uint32("num_als_usrs1", ps, depth, &(r_u->num_als_usrs1));
+ prs_uint32("ptr_als_usrs ", ps, depth, &(r_u->ptr_als_usrs ));
+ prs_uint32("num_als_usrs2", ps, depth, &(r_u->num_als_usrs2));
+
+ if (r_u->ptr_als_usrs != 0 && r_u->num_als_usrs1 != 0)
+ {
+ SMB_ASSERT_ARRAY(r_u->num_als_usrs, r_u->num_als_usrs2);
+
+ for (i = 0; i < r_u->num_als_usrs2; i++)
+ {
+ slprintf(tmp, sizeof(tmp) - 1, "als_usrs[%02d] ", i);
+ prs_uint32(tmp, ps, depth, &(r_u->num_als_usrs[i]));
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void make_samr_q_open_user(SAMR_Q_OPEN_USER *q_u,
+ POLICY_HND *pol,
+ uint32 unk_0, uint32 rid)
+{
+ if (q_u == NULL) return;
+
+ DEBUG(5,("samr_make_q_open_user\n"));
+
+ memcpy(&q_u->domain_pol, pol, sizeof(q_u->domain_pol));
+
+ q_u->unknown_0 = unk_0;
+ q_u->user_rid = rid;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_open_user(char *desc, SAMR_Q_OPEN_USER *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_user");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("domain_pol", &(q_u->domain_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("unknown_0", ps, depth, &(q_u->unknown_0));
+ prs_uint32("user_rid ", ps, depth, &(q_u->user_rid ));
+
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_open_user(char *desc, SAMR_R_OPEN_USER *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_user");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("user_pol", &(r_u->user_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+makes a SAMR_Q_QUERY_USERGROUPS structure.
+********************************************************************/
+void make_samr_q_query_usergroups(SAMR_Q_QUERY_USERGROUPS *q_u,
+ POLICY_HND *hnd)
+{
+ if (q_u == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_samr_q_query_usergroups\n"));
+
+ memcpy(&(q_u->pol), hnd, sizeof(q_u->pol));
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_query_usergroups(char *desc, SAMR_Q_QUERY_USERGROUPS *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_usergroups");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+}
+
+/*******************************************************************
+makes a SAMR_R_QUERY_USERGROUPS structure.
+********************************************************************/
+void make_samr_r_query_usergroups(SAMR_R_QUERY_USERGROUPS *r_u,
+ uint32 num_gids, DOM_GID *gid, uint32 status)
+{
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_query_usergroups\n"));
+
+ if (status == 0x0)
+ {
+ r_u->ptr_0 = 1;
+ r_u->num_entries = num_gids;
+ r_u->ptr_1 = 1;
+ 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->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_query_usergroups(char *desc, SAMR_R_QUERY_USERGROUPS *r_u, prs_struct *ps, int depth)
+{
+ int i;
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_usergroups");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_0 ", ps, depth, &(r_u->ptr_0 ));
+
+ if (r_u->ptr_0 != 0)
+ {
+ prs_uint32("num_entries ", ps, depth, &(r_u->num_entries));
+ prs_uint32("ptr_1 ", ps, depth, &(r_u->ptr_1 ));
+
+ if (r_u->num_entries != 0)
+ {
+ prs_uint32("num_entries2", ps, depth, &(r_u->num_entries2));
+
+ for (i = 0; i < r_u->num_entries2; i++)
+ {
+ smb_io_gid("", &(r_u->gid[i]), ps, depth);
+ }
+ }
+ }
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+makes a SAMR_Q_QUERY_USERINFO structure.
+********************************************************************/
+void make_samr_q_query_userinfo(SAMR_Q_QUERY_USERINFO *q_u,
+ POLICY_HND *hnd, uint16 switch_value)
+{
+ if (q_u == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_samr_q_query_userinfo\n"));
+
+ memcpy(&(q_u->pol), hnd, sizeof(q_u->pol));
+ q_u->switch_value = switch_value;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_query_userinfo(char *desc, SAMR_Q_QUERY_USERINFO *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_query_userinfo");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_value", ps, depth, &(q_u->switch_value)); /* 0x0015 or 0x0011 */
+
+ prs_align(ps);
+}
+
+/*******************************************************************
+reads or writes a LOGON_HRS structure.
+********************************************************************/
+static void sam_io_logon_hrs(char *desc, LOGON_HRS *hrs, prs_struct *ps, int depth)
+{
+ if (hrs == NULL) return;
+
+ prs_debug(ps, depth, desc, "sam_io_logon_hrs");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32 ( "len ", ps, depth, &(hrs->len ));
+
+ if (hrs->len > 64)
+ {
+ DEBUG(5,("sam_io_logon_hrs: truncating length\n"));
+ hrs->len = 64;
+ }
+
+ prs_uint8s (False, "hours", ps, depth, hrs->hours, hrs->len);
+}
+
+/*************************************************************************
+ make_sam_user_info21
+
+ unknown_3 = 0x00ff ffff
+ unknown_5 = 0x0002 0000
+ unknown_6 = 0x0000 04ec
+
+ *************************************************************************/
+void make_sam_user_info21(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,
+
+ char *user_name,
+ char *full_name,
+ char *home_dir,
+ char *dir_drive,
+ char *logon_script,
+ char *profile_path,
+ char *description,
+ char *workstations,
+ char *unknown_str,
+ char *munged_dial,
+
+ uint32 user_rid,
+ uint32 group_rid,
+ uint16 acb_info,
+
+ uint32 unknown_3,
+ uint16 logon_divs,
+ LOGON_HRS *hrs,
+ uint32 unknown_5,
+ 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 = logon_script != NULL ? strlen(logon_script) : 0;
+ int len_profile_path = profile_path != NULL ? strlen(profile_path) : 0;
+ int len_description = description != NULL ? strlen(description ) : 0;
+ int len_workstations = workstations != NULL ? strlen(workstations) : 0;
+ int len_unknown_str = unknown_str != NULL ? strlen(unknown_str ) : 0;
+ int len_munged_dial = munged_dial != NULL ? strlen(munged_dial ) : 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;
+
+ make_uni_hdr(&(usr->hdr_user_name ), len_user_name , len_user_name , len_user_name != 0);
+ make_uni_hdr(&(usr->hdr_full_name ), len_full_name , len_full_name , len_full_name != 0);
+ make_uni_hdr(&(usr->hdr_home_dir ), len_home_dir , len_home_dir , len_home_dir != 0);
+ make_uni_hdr(&(usr->hdr_dir_drive ), len_dir_drive , len_dir_drive , len_dir_drive != 0);
+ make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, len_logon_script != 0);
+ make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, len_profile_path != 0);
+ make_uni_hdr(&(usr->hdr_acct_desc ), len_description , len_description , len_description != 0);
+ make_uni_hdr(&(usr->hdr_workstations), len_workstations, len_workstations, len_workstations != 0);
+ make_uni_hdr(&(usr->hdr_unknown_str ), len_unknown_str , len_unknown_str , len_workstations != 0);
+ make_uni_hdr(&(usr->hdr_munged_dial ), len_munged_dial , len_munged_dial , len_workstations != 0);
+
+ bzero(usr->nt_pwd, sizeof(usr->nt_pwd));
+ bzero(usr->lm_pwd, sizeof(usr->lm_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 */
+
+ bzero(usr->padding1, sizeof(usr->padding1));
+
+ make_unistr2(&(usr->uni_user_name ), user_name , len_user_name );
+ make_unistr2(&(usr->uni_full_name ), full_name , len_full_name );
+ make_unistr2(&(usr->uni_home_dir ), home_dir , len_home_dir );
+ make_unistr2(&(usr->uni_dir_drive ), dir_drive , len_dir_drive );
+ make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script);
+ make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path);
+ make_unistr2(&(usr->uni_acct_desc ), description , len_description );
+ make_unistr2(&(usr->uni_workstations), workstations, len_workstations);
+ make_unistr2(&(usr->uni_unknown_str ), unknown_str , len_unknown_str );
+ make_unistr2(&(usr->uni_munged_dial ), munged_dial , len_munged_dial );
+
+ usr->unknown_6 = unknown_6; /* 0x0000 04ec */
+ usr->padding4 = 0;
+
+ if (hrs)
+ {
+ memcpy(&(usr->logon_hrs), hrs, sizeof(usr->logon_hrs));
+ }
+ else
+ {
+ memset(&(usr->logon_hrs), 0xff, sizeof(usr->logon_hrs));
+ }
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void sam_io_user_info21(char *desc, SAM_USER_INFO_21 *usr, prs_struct *ps, int depth)
+{
+ if (usr == NULL) return;
+
+ prs_debug(ps, depth, desc, "lsa_io_user_info");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_time("logon_time ", &(usr->logon_time) , ps, depth);
+ smb_io_time("logoff_time ", &(usr->logoff_time) , ps, depth);
+ smb_io_time("kickoff_time ", &(usr->kickoff_time) , ps, depth);
+ smb_io_time("pass_last_set_time ", &(usr->pass_last_set_time) , ps, depth);
+ smb_io_time("pass_can_change_time ", &(usr->pass_can_change_time) , ps, depth);
+ smb_io_time("pass_must_change_time", &(usr->pass_must_change_time), ps, depth);
+
+ smb_io_unihdr("hdr_user_name ", &(usr->hdr_user_name) , ps, depth); /* username unicode string header */
+ smb_io_unihdr("hdr_full_name ", &(usr->hdr_full_name) , ps, depth); /* user's full name unicode string header */
+ smb_io_unihdr("hdr_home_dir ", &(usr->hdr_home_dir) , ps, depth); /* home directory unicode string header */
+ smb_io_unihdr("hdr_dir_drive ", &(usr->hdr_dir_drive) , ps, depth); /* home directory drive */
+ smb_io_unihdr("hdr_logon_script", &(usr->hdr_logon_script), ps, depth); /* logon script unicode string header */
+ smb_io_unihdr("hdr_profile_path", &(usr->hdr_profile_path), ps, depth); /* profile path unicode string header */
+ smb_io_unihdr("hdr_acct_desc ", &(usr->hdr_acct_desc ) , ps, depth); /* account description */
+ smb_io_unihdr("hdr_workstations", &(usr->hdr_workstations), ps, depth); /* workstations user can log on from */
+ smb_io_unihdr("hdr_unknown_str ", &(usr->hdr_unknown_str ), ps, depth); /* unknown string */
+ smb_io_unihdr("hdr_munged_dial ", &(usr->hdr_munged_dial ), ps, depth); /* workstations user can log on from */
+
+ prs_uint8s (False, "lm_pwd ", ps, depth, usr->lm_pwd , sizeof(usr->lm_pwd ));
+ prs_uint8s (False, "nt_pwd ", ps, depth, usr->nt_pwd , sizeof(usr->nt_pwd ));
+
+ prs_uint32("user_rid ", ps, depth, &(usr->user_rid )); /* User ID */
+ prs_uint32("group_rid ", ps, depth, &(usr->group_rid )); /* Group ID */
+ prs_uint16("acb_info ", ps, depth, &(usr->acb_info )); /* Group ID */
+ prs_align(ps);
+
+ prs_uint32("unknown_3 ", ps, depth, &(usr->unknown_3 ));
+ prs_uint16("logon_divs ", ps, depth, &(usr->logon_divs )); /* logon divisions per week */
+ prs_align(ps);
+ prs_uint32("ptr_logon_hrs ", ps, depth, &(usr->ptr_logon_hrs));
+ prs_uint32("unknown_5 ", ps, depth, &(usr->unknown_5 ));
+
+ prs_uint8s (False, "padding1 ", ps, depth, usr->padding1, sizeof(usr->padding1));
+
+ /* here begins pointed-to data */
+
+ smb_io_unistr2("uni_user_name ", &(usr->uni_user_name) , usr->hdr_user_name .buffer, ps, depth); /* username unicode string */
+ smb_io_unistr2("uni_full_name ", &(usr->uni_full_name) , usr->hdr_full_name .buffer, ps, depth); /* user's full name unicode string */
+ smb_io_unistr2("uni_home_dir ", &(usr->uni_home_dir) , usr->hdr_home_dir .buffer, ps, depth); /* home directory unicode string */
+ smb_io_unistr2("uni_dir_drive ", &(usr->uni_dir_drive) , usr->hdr_dir_drive .buffer, ps, depth); /* home directory drive unicode string */
+ smb_io_unistr2("uni_logon_script", &(usr->uni_logon_script), usr->hdr_logon_script.buffer, ps, depth); /* logon script unicode string */
+ smb_io_unistr2("uni_profile_path", &(usr->uni_profile_path), usr->hdr_profile_path.buffer, ps, depth); /* profile path unicode string */
+ smb_io_unistr2("uni_acct_desc ", &(usr->uni_acct_desc ), usr->hdr_acct_desc .buffer, ps, depth); /* user description unicode string */
+ smb_io_unistr2("uni_workstations", &(usr->uni_workstations), usr->hdr_workstations.buffer, ps, depth); /* worksations user can log on from */
+ smb_io_unistr2("uni_unknown_str ", &(usr->uni_unknown_str ), usr->hdr_unknown_str .buffer, ps, depth); /* unknown string */
+ smb_io_unistr2("uni_munged_dial ", &(usr->uni_munged_dial ), usr->hdr_munged_dial .buffer, ps, depth); /* worksations user can log on from */
+
+ prs_uint32("unknown_6 ", ps, depth, &(usr->unknown_6 ));
+ prs_uint32("padding4 ", ps, depth, &(usr->padding4 ));
+
+ if (usr->ptr_logon_hrs)
+ {
+ sam_io_logon_hrs("logon_hrs", &(usr->logon_hrs) , ps, depth);
+ prs_align(ps);
+ }
+}
+
+
+/*******************************************************************
+makes a SAMR_R_QUERY_USERINFO structure.
+********************************************************************/
+void make_samr_r_query_userinfo(SAMR_R_QUERY_USERINFO *r_u,
+ uint16 switch_value, void *info, uint32 status)
+
+{
+ if (r_u == NULL || info == NULL) return;
+
+ DEBUG(5,("make_samr_r_query_userinfo\n"));
+
+ r_u->ptr = 0;
+ r_u->switch_value = 0;
+
+ if (status == 0)
+ {
+ r_u->switch_value = switch_value;
+
+ switch (switch_value)
+ {
+ case 0x10:
+ {
+ r_u->ptr = 1;
+ r_u->info.id10 = (SAM_USER_INFO_10*)info;
+
+ break;
+ }
+
+ case 0x11:
+ {
+ r_u->ptr = 1;
+ r_u->info.id11 = (SAM_USER_INFO_11*)info;
+
+ break;
+ }
+
+ case 21:
+ {
+ r_u->ptr = 1;
+ r_u->info.id21 = (SAM_USER_INFO_21*)info;
+
+ break;
+ }
+
+ default:
+ {
+ DEBUG(4,("make_samr_r_query_aliasinfo: unsupported switch level\n"));
+ break;
+ }
+ }
+ }
+
+ r_u->status = status; /* return status */
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_query_userinfo(char *desc, SAMR_R_QUERY_USERINFO *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_query_userinfo");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr ", ps, depth, &(r_u->ptr ));
+ prs_uint16("switch_value", ps, depth, &(r_u->switch_value));
+ prs_align(ps);
+
+ if (r_u->ptr != 0 && r_u->switch_value != 0)
+ {
+ switch (r_u->switch_value)
+ {
+/*
+ case 0x10:
+ {
+ if (r_u->info.id10 != NULL)
+ {
+ sam_io_user_info10("", r_u->info.id10, ps, depth);
+ }
+ else
+ {
+ DEBUG(2,("samr_io_r_query_userinfo: info pointer not initialised\n"));
+ return NULL;
+ }
+ break;
+ }
+ case 0x11:
+ {
+ if (r_u->info.id11 != NULL)
+ {
+ sam_io_user_info11("", r_u->info.id11, ps, depth);
+ }
+ else
+ {
+ DEBUG(2,("samr_io_r_query_userinfo: info pointer not initialised\n"));
+ return NULL;
+ }
+ break;
+ }
+*/
+ case 21:
+ {
+ if (r_u->info.id21 != NULL)
+ {
+ sam_io_user_info21("", r_u->info.id21, ps, depth);
+ }
+ else
+ {
+ DEBUG(2,("samr_io_r_query_userinfo: info pointer not initialised\n"));
+ return;
+ }
+ break;
+ }
+ default:
+ {
+ DEBUG(2,("samr_io_r_query_userinfo: unknown switch level\n"));
+ break;
+ }
+
+ }
+ }
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_unknown_32(char *desc, SAMR_Q_UNKNOWN_32 *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_32");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(q_u->pol), ps, depth);
+ prs_align(ps);
+
+ smb_io_unihdr ("", &(q_u->hdr_mach_acct), ps, depth);
+ smb_io_unistr2("", &(q_u->uni_mach_acct), q_u->hdr_mach_acct.buffer, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("acct_ctrl", ps, depth, &(q_u->acct_ctrl));
+ prs_uint16("unknown_1", ps, depth, &(q_u->unknown_1));
+ prs_uint16("unknown_2", ps, depth, &(q_u->unknown_2));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_unknown_32(char *desc, SAMR_R_UNKNOWN_32 *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_unknown_32");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(r_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+/*******************************************************************
+makes a SAMR_Q_CONNECT structure.
+********************************************************************/
+void make_samr_q_connect(SAMR_Q_CONNECT *q_u,
+ char *srv_name, uint32 unknown_0)
+{
+ int len_srv_name = strlen(srv_name);
+
+ if (q_u == NULL) return;
+
+ DEBUG(5,("make_q_connect\n"));
+
+ /* make PDC server name \\server */
+ make_unistr2(&(q_u->uni_srv_name), srv_name, len_srv_name);
+
+ /* example values: 0x0000 0002 */
+ q_u->unknown_0 = unknown_0;
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_connect(char *desc, SAMR_Q_CONNECT *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_connect");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name", ps, depth, &(q_u->ptr_srv_name));
+ smb_io_unistr2("", &(q_u->uni_srv_name), q_u->ptr_srv_name, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("unknown_0 ", ps, depth, &(q_u->unknown_0 ));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_connect(char *desc, SAMR_R_CONNECT *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_connect");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("connect_pol", &(r_u->connect_pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+makes a SAMR_Q_OPEN_ALIAS structure.
+********************************************************************/
+void make_samr_q_open_alias(SAMR_Q_OPEN_ALIAS *q_u,
+ uint32 unknown_0, uint32 rid)
+{
+ if (q_u == NULL) return;
+
+ DEBUG(5,("make_q_open_alias\n"));
+
+ /* example values: 0x0000 0008 */
+ q_u->unknown_0 = unknown_0;
+
+ q_u->rid_alias = rid;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_open_alias(char *desc, SAMR_Q_OPEN_ALIAS *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_open_alias");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("unknown_0", ps, depth, &(q_u->unknown_0));
+ prs_uint32("rid_alias", ps, depth, &(q_u->rid_alias));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_open_alias(char *desc, SAMR_R_OPEN_ALIAS *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_open_alias");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_pol_hnd("pol", &(r_u->pol), ps, depth);
+ prs_align(ps);
+
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+
+#if 0
+/* SAMR_Q_CHGPASSWD_USER */
+typedef struct q_samr_chgpasswd_user_info
+{
+ uint32 ptr_0;
+
+ UNIHDR hdr_server; /* server name unicode header */
+ UNISTR2 uni_server; /* 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_1; /* seems to always contain 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
+{
+ uint32 result; /* 0 == OK, C000006A (NT_STATUS_WRONG_PASSWORD) */
+
+} SAMR_R_CHGPASSWD_USER;
+
+#endif /* 0 */
+
+
+/*******************************************************************
+makes a SAMR_Q_UNKNOWN_38 structure.
+********************************************************************/
+void make_samr_q_unknown_38(SAMR_Q_UNKNOWN_38 *q_u, char *srv_name)
+{
+ int len_srv_name = strlen(srv_name);
+
+ if (q_u == NULL) return;
+
+ DEBUG(5,("make_q_unknown_38\n"));
+
+ q_u->ptr = 1;
+ make_uni_hdr(&(q_u->hdr_srv_name), len_srv_name, len_srv_name, len_srv_name != 0);
+ make_unistr2(&(q_u->uni_srv_name), srv_name, len_srv_name);
+
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_q_unknown_38(char *desc, SAMR_Q_UNKNOWN_38 *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_q_unknown_38");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr", ps, depth, &(q_u->ptr));
+ if (q_u->ptr != 0)
+ {
+ smb_io_unihdr ("", &(q_u->hdr_srv_name), ps, depth);
+ smb_io_unistr2("", &(q_u->uni_srv_name), q_u->hdr_srv_name.buffer, ps, depth);
+ }
+}
+
+/*******************************************************************
+makes a SAMR_R_UNKNOWN_38 structure.
+********************************************************************/
+void make_samr_r_unknown_38(SAMR_R_UNKNOWN_38 *r_u,
+ uint16 level, uint32 status)
+{
+ if (r_u == NULL) return;
+
+ DEBUG(5,("make_r_unknown_38\n"));
+
+ r_u->level.value = level;
+ r_u->ptr_0 = 0;
+ r_u->status = status;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void samr_io_r_unknown_38(char *desc, SAMR_R_UNKNOWN_38 *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_r_unknown_38");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_lookup_level("level ", &(r_u->level), ps, depth);
+ prs_uint32("ptr_0 ", ps, depth, &(r_u->ptr_0 ));
+ prs_uint32("status", ps, depth, &(r_u->status));
+}
+
+/*******************************************************************
+reads or writes a SAMR_ENC_PASSWD structure.
+********************************************************************/
+void samr_io_enc_passwd(char *desc, SAMR_ENC_PASSWD *pwd, prs_struct *ps, int depth)
+{
+ if (pwd == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_enc_passwd");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr", ps, depth, &(pwd->ptr));
+ prs_uint8s(False, "pwd", ps, depth, pwd->pass, sizeof(pwd->pass));
+}
+
+/*******************************************************************
+reads or writes a SAMR_ENC_HASH structure.
+********************************************************************/
+void samr_io_enc_hash(char *desc, SAMR_ENC_HASH *hsh, prs_struct *ps, int depth)
+{
+ if (hsh == NULL) return;
+
+ prs_debug(ps, depth, desc, "samr_io_enc_hash");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr ", ps, depth, &(hsh->ptr));
+ prs_uint8s(False, "hash", ps, depth, hsh->hash, sizeof(hsh->hash));
+}
+
+#if 0
+/* SAMR_Q_CHGPASSWD_USER */
+typedef struct q_samr_chgpasswd_user_info
+{
+ uint32 ptr_0;
+
+ UNIHDR hdr_server; /* server name unicode header */
+ UNISTR2 uni_server; /* 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_1; /* seems to always contain 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
+{
+ uint32 result; /* 0 == OK, C000006A (NT_STATUS_WRONG_PASSWORD) */
+
+} SAMR_R_CHGPASSWD_USER;
+
+#endif /* 0 */
+
+
+/*******************************************************************
+makes a SAMR_Q_UNKNOWN_12 structure.
+********************************************************************/
+void make_samr_q_unknown_12(SAMR_Q_UNKNOWN_12 *q_u,
+ POLICY_HND *pol, uint32 rid,
+ uint32 num_gids, uint32 *gid)
+{
+ int i;
+ if (q_u == NULL) return;
+
+ DEBUG(5,("make_samr_r_unknwon_12\n"));
+
+ memcpy(&(q_u->pol), pol, sizeof(*pol));
+
+ q_u->num_gids1 = num_gids;
+ q_u->rid = rid;
+ q_u->ptr = 0;
+ q_u->num_gids2 = num_gids;
+
+ for (i = 0; i < num_gids; i++)
+ {
+ q_u->gid[i] = gid[i];
+ }
+}
+
+
+
+
+/*******************************************************************
+makes a SAMR_Q_UNKNOWN_21 structure.
+********************************************************************/
+void make_samr_q_unknown_21(SAMR_Q_UNKNOWN_21 *q_c,
+ POLICY_HND *hnd, uint16 unk_1, uint16 unk_2)
+{
+ if (q_c == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_samr_q_unknown_21\n"));
+
+ memcpy(&(q_c->group_pol), hnd, sizeof(q_c->group_pol));
+ q_c->unknown_1 = unk_1;
+ q_c->unknown_2 = unk_2;
+}
+
+
+/*******************************************************************
+makes a SAMR_Q_UNKNOWN_13 structure.
+********************************************************************/
+void make_samr_q_unknown_13(SAMR_Q_UNKNOWN_13 *q_c,
+ POLICY_HND *hnd, uint16 unk_1, uint16 unk_2)
+{
+ if (q_c == NULL || hnd == NULL) return;
+
+ DEBUG(5,("make_samr_q_unknown_13\n"));
+
+ memcpy(&(q_c->alias_pol), hnd, sizeof(q_c->alias_pol));
+ q_c->unknown_1 = unk_1;
+ q_c->unknown_2 = unk_2;
+}
+
+
diff --git a/source/rpc_parse/parse_srv.c b/source/rpc_parse/parse_srv.c
new file mode 100644
index 00000000000..882ad9e59d6
--- /dev/null
+++ b/source/rpc_parse/parse_srv.c
@@ -0,0 +1,1440 @@
+
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+ makes a SH_INFO_1_STR structure
+********************************************************************/
+void make_srv_share_info1_str(SH_INFO_1_STR *sh1, char *net_name, char *remark)
+{
+ if (sh1 == NULL) return;
+
+ DEBUG(5,("make_srv_share_info1_str\n"));
+
+ make_unistr2(&(sh1->uni_netname), net_name, strlen(net_name));
+ make_unistr2(&(sh1->uni_remark ), remark , strlen(remark ));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_share_info1_str(char *desc, SH_INFO_1_STR *sh1, prs_struct *ps, int depth)
+{
+ if (sh1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info1_str");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("", &(sh1->uni_netname), True, ps, depth);
+ smb_io_unistr2("", &(sh1->uni_remark ), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a SH_INFO_1 structure
+********************************************************************/
+void make_srv_share_info1(SH_INFO_1 *sh1, char *net_name, uint32 type, char *remark)
+{
+ if (sh1 == NULL) return;
+
+ DEBUG(5,("make_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 void srv_io_share_info1(char *desc, SH_INFO_1 *sh1, prs_struct *ps, int depth)
+{
+ if (sh1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_netname", ps, depth, &(sh1->ptr_netname));
+ prs_uint32("type ", ps, depth, &(sh1->type ));
+ prs_uint32("ptr_remark ", ps, depth, &(sh1->ptr_remark));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_share_info_1(char *desc, SRV_SHARE_INFO_1 *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_share_1_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(ctr->num_entries_read));
+ prs_uint32("ptr_share_info", ps, depth, &(ctr->ptr_share_info));
+
+ if (ctr->ptr_share_info != 0)
+ {
+ int i;
+ int num_entries = ctr->num_entries_read;
+ if (num_entries > MAX_SHARE_ENTRIES)
+ {
+ num_entries = MAX_SHARE_ENTRIES; /* report this! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(ctr->num_entries_read2));
+
+ SMB_ASSERT_ARRAY(ctr->info_1, num_entries);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_share_info1("", &(ctr->info_1[i]), ps, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_share_info1_str("", &(ctr->info_1_str[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+ makes a SH_INFO_2_STR structure
+********************************************************************/
+void make_srv_share_info2_str(SH_INFO_2_STR *sh2,
+ char *net_name, char *remark,
+ char *path, char *passwd)
+{
+ if (sh2 == NULL) return;
+
+ DEBUG(5,("make_srv_share_info2_str\n"));
+
+ make_unistr2(&(sh2->uni_netname), net_name, strlen(net_name)+1);
+ make_unistr2(&(sh2->uni_remark ), remark , strlen(remark )+1);
+ make_unistr2(&(sh2->uni_path ), path , strlen(path )+1);
+ make_unistr2(&(sh2->uni_passwd ), passwd , strlen(passwd )+1);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_share_info2_str(char *desc, SH_INFO_2_STR *sh2, prs_struct *ps, int depth)
+{
+ if (sh2 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info2_str");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("", &(sh2->uni_netname), True, ps, depth);
+ smb_io_unistr2("", &(sh2->uni_remark ), True, ps, depth);
+ smb_io_unistr2("", &(sh2->uni_path ), True, ps, depth);
+ smb_io_unistr2("", &(sh2->uni_passwd ), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a SH_INFO_2 structure
+********************************************************************/
+void make_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)
+{
+ if (sh2 == NULL) return;
+
+ DEBUG(5,("make_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 void srv_io_share_info2(char *desc, SH_INFO_2 *sh2, prs_struct *ps, int depth)
+{
+ if (sh2 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_share_info2");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_netname", ps, depth, &(sh2->ptr_netname));
+ prs_uint32("type ", ps, depth, &(sh2->type ));
+ prs_uint32("ptr_remark ", ps, depth, &(sh2->ptr_remark ));
+ prs_uint32("perms ", ps, depth, &(sh2->perms ));
+ prs_uint32("max_uses ", ps, depth, &(sh2->max_uses ));
+ prs_uint32("num_uses ", ps, depth, &(sh2->num_uses ));
+ prs_uint32("ptr_path ", ps, depth, &(sh2->ptr_path ));
+ prs_uint32("ptr_passwd ", ps, depth, &(sh2->ptr_passwd ));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_share_info_2(char *desc, SRV_SHARE_INFO_2 *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_share_2_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(ctr->num_entries_read));
+ prs_uint32("ptr_share_info", ps, depth, &(ctr->ptr_share_info));
+
+ if (ctr->ptr_share_info != 0)
+ {
+ int i;
+ int num_entries = ctr->num_entries_read;
+ if (num_entries > MAX_SHARE_ENTRIES)
+ {
+ num_entries = MAX_SHARE_ENTRIES; /* report this! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(ctr->num_entries_read2));
+
+ SMB_ASSERT_ARRAY(ctr->info_2, num_entries);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_share_info2("", &(ctr->info_2[i]), ps, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_share_info2_str("", &(ctr->info_2_str[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_share_ctr(char *desc, SRV_SHARE_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_share_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("switch_value", ps, depth, &(ctr->switch_value));
+ prs_uint32("ptr_share_ctr", ps, depth, &(ctr->ptr_share_ctr));
+
+ if (ctr->ptr_share_ctr != 0)
+ {
+ switch (ctr->switch_value)
+ {
+ case 2:
+ {
+ srv_io_srv_share_info_2("", &(ctr->share.info2), ps, depth);
+ break;
+ }
+ case 1:
+ {
+ srv_io_srv_share_info_1("", &(ctr->share.info1), ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s no share info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_share_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name", ps, depth, &(q_n->ptr_srv_name));
+ smb_io_unistr2("", &(q_n->uni_srv_name), True, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("share_level", ps, depth, &(q_n->share_level ));
+
+ if (q_n->share_level != -1)
+ {
+ srv_io_srv_share_ctr("share_ctr", q_n->ctr, ps, depth);
+ }
+
+ prs_uint32("preferred_len", ps, depth, &(q_n->preferred_len));
+
+ smb_io_enum_hnd("enum_hnd", &(q_n->enum_hnd), ps, depth);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_share_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("share_level", ps, depth, &(r_n->share_level));
+
+ if (r_n->share_level != 0)
+ {
+ srv_io_srv_share_ctr("share_ctr", r_n->ctr, ps, depth);
+ }
+
+ prs_uint32("total_entries", ps, depth, &(r_n->total_entries));
+ smb_io_enum_hnd("enum_hnd", &(r_n->enum_hnd), ps, depth);
+ prs_uint32("status ", ps, depth, &(r_n->status));
+}
+
+/*******************************************************************
+ makes a SESS_INFO_0_STR structure
+********************************************************************/
+void make_srv_sess_info0_str(SESS_INFO_0_STR *ss0, char *name)
+{
+ if (ss0 == NULL) return;
+
+ DEBUG(5,("make_srv_sess_info0_str\n"));
+
+ make_unistr2(&(ss0->uni_name), name, strlen(name));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_sess_info0_str(char *desc, SESS_INFO_0_STR *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info0_str");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("", &(ss0->uni_name), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a SESS_INFO_0 structure
+********************************************************************/
+void make_srv_sess_info0(SESS_INFO_0 *ss0, char *name)
+{
+ if (ss0 == NULL) return;
+
+ DEBUG(5,("make_srv_sess_info0: %s\n", name));
+
+ ss0->ptr_name = name != NULL ? 1 : 0;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_sess_info0(char *desc, SESS_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info0");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_name", ps, depth, &(ss0->ptr_name));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_sess_info_0(char *desc, SRV_SESS_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_sess_info_0");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(ss0->num_entries_read));
+ prs_uint32("ptr_sess_info", ps, depth, &(ss0->ptr_sess_info));
+
+ 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! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(ss0->num_entries_read2));
+
+ SMB_ASSERT_ARRAY(ss0->info_0, num_entries);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_sess_info0("", &(ss0->info_0[i]), ps, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_sess_info0_str("", &(ss0->info_0_str[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+ makes a SESS_INFO_1_STR structure
+********************************************************************/
+void make_srv_sess_info1_str(SESS_INFO_1_STR *ss1, char *name, char *user)
+{
+ if (ss1 == NULL) return;
+
+ DEBUG(5,("make_srv_sess_info1_str\n"));
+
+ make_unistr2(&(ss1->uni_name), name, strlen(name));
+ make_unistr2(&(ss1->uni_user), name, strlen(user));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_sess_info1_str(char *desc, SESS_INFO_1_STR *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info1_str");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("", &(ss1->uni_name), True, ps, depth);
+ smb_io_unistr2("", &(ss1->uni_user), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a SESS_INFO_1 structure
+********************************************************************/
+void make_srv_sess_info1(SESS_INFO_1 *ss1,
+ char *name, char *user,
+ uint32 num_opens, uint32 open_time, uint32 idle_time,
+ uint32 user_flags)
+{
+ if (ss1 == NULL) return;
+
+ DEBUG(5,("make_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 void srv_io_sess_info1(char *desc, SESS_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_sess_info1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_name ", ps, depth, &(ss1->ptr_name ));
+ prs_uint32("ptr_user ", ps, depth, &(ss1->ptr_user ));
+
+ prs_uint32("num_opens ", ps, depth, &(ss1->num_opens ));
+ prs_uint32("open_time ", ps, depth, &(ss1->open_time ));
+ prs_uint32("idle_time ", ps, depth, &(ss1->idle_time ));
+ prs_uint32("user_flags", ps, depth, &(ss1->user_flags));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_sess_info_1(char *desc, SRV_SESS_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_sess_info_1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(ss1->num_entries_read));
+ prs_uint32("ptr_sess_info", ps, depth, &(ss1->ptr_sess_info));
+
+ 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! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(ss1->num_entries_read2));
+
+ SMB_ASSERT_ARRAY(ss1->info_1, num_entries);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_sess_info1("", &(ss1->info_1[i]), ps, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_sess_info1_str("", &(ss1->info_1_str[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_sess_ctr(char *desc, SRV_SESS_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_sess_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("switch_value", ps, depth, &(ctr->switch_value));
+ prs_uint32("ptr_sess_ctr", ps, depth, &(ctr->ptr_sess_ctr));
+
+ if (ctr->ptr_sess_ctr != 0)
+ {
+ switch (ctr->switch_value)
+ {
+ case 0:
+ {
+ srv_io_srv_sess_info_0("", &(ctr->sess.info0), ps, depth);
+ break;
+ }
+ case 1:
+ {
+ srv_io_srv_sess_info_1("", &(ctr->sess.info1), ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s no session info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_sess_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name", ps, depth, &(q_n->ptr_srv_name));
+ smb_io_unistr2("", &(q_n->uni_srv_name), True, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("ptr_qual_name", ps, depth, &(q_n->ptr_qual_name));
+ smb_io_unistr2("", &(q_n->uni_qual_name), q_n->ptr_qual_name, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("sess_level", ps, depth, &(q_n->sess_level ));
+
+ if (q_n->sess_level != -1)
+ {
+ srv_io_srv_sess_ctr("sess_ctr", q_n->ctr, ps, depth);
+ }
+
+ prs_uint32("preferred_len", ps, depth, &(q_n->preferred_len));
+
+ smb_io_enum_hnd("enum_hnd", &(q_n->enum_hnd), ps, depth);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_sess_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("sess_level", ps, depth, &(r_n->sess_level));
+
+ if (r_n->sess_level != -1)
+ {
+ srv_io_srv_sess_ctr("sess_ctr", r_n->ctr, ps, depth);
+ }
+
+ prs_uint32("total_entries", ps, depth, &(r_n->total_entries));
+ smb_io_enum_hnd("enum_hnd", &(r_n->enum_hnd), ps, depth);
+ prs_uint32("status ", ps, depth, &(r_n->status));
+}
+
+/*******************************************************************
+ makes a CONN_INFO_0 structure
+********************************************************************/
+void make_srv_conn_info0(CONN_INFO_0 *ss0, uint32 id)
+{
+ if (ss0 == NULL) return;
+
+ DEBUG(5,("make_srv_conn_info0\n"));
+
+ ss0->id = id;
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_conn_info0(char *desc, CONN_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_conn_info0");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("id", ps, depth, &(ss0->id));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_conn_info_0(char *desc, SRV_CONN_INFO_0 *ss0, prs_struct *ps, int depth)
+{
+ if (ss0 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_conn_info_0");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(ss0->num_entries_read));
+ prs_uint32("ptr_conn_info", ps, depth, &(ss0->ptr_conn_info));
+
+ 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! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(ss0->num_entries_read2));
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_conn_info0("", &(ss0->info_0[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+ makes a CONN_INFO_1_STR structure
+********************************************************************/
+void make_srv_conn_info1_str(CONN_INFO_1_STR *ss1, char *usr_name, char *net_name)
+{
+ if (ss1 == NULL) return;
+
+ DEBUG(5,("make_srv_conn_info1_str\n"));
+
+ make_unistr2(&(ss1->uni_usr_name), usr_name, strlen(usr_name));
+ make_unistr2(&(ss1->uni_net_name), net_name, strlen(net_name));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_conn_info1_str(char *desc, CONN_INFO_1_STR *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_conn_info1_str");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("", &(ss1->uni_usr_name), True, ps, depth);
+ smb_io_unistr2("", &(ss1->uni_net_name), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a CONN_INFO_1 structure
+********************************************************************/
+void make_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)
+{
+ if (ss1 == NULL) return;
+
+ DEBUG(5,("make_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 void srv_io_conn_info1(char *desc, CONN_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_conn_info1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("id ", ps, depth, &(ss1->id ));
+ prs_uint32("type ", ps, depth, &(ss1->type ));
+ prs_uint32("num_opens ", ps, depth, &(ss1->num_opens ));
+ prs_uint32("num_users ", ps, depth, &(ss1->num_users ));
+ prs_uint32("open_time ", ps, depth, &(ss1->open_time ));
+
+ prs_uint32("ptr_usr_name", ps, depth, &(ss1->ptr_usr_name));
+ prs_uint32("ptr_net_name", ps, depth, &(ss1->ptr_net_name));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_conn_info_1(char *desc, SRV_CONN_INFO_1 *ss1, prs_struct *ps, int depth)
+{
+ if (ss1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_conn_info_1");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(ss1->num_entries_read));
+ prs_uint32("ptr_conn_info", ps, depth, &(ss1->ptr_conn_info));
+
+ 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! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(ss1->num_entries_read2));
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_conn_info1("", &(ss1->info_1[i]), ps, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_conn_info1_str("", &(ss1->info_1_str[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_conn_ctr(char *desc, SRV_CONN_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_conn_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("switch_value", ps, depth, &(ctr->switch_value));
+ prs_uint32("ptr_conn_ctr", ps, depth, &(ctr->ptr_conn_ctr));
+
+ if (ctr->ptr_conn_ctr != 0)
+ {
+ switch (ctr->switch_value)
+ {
+ case 0:
+ {
+ srv_io_srv_conn_info_0("", &(ctr->conn.info0), ps, depth);
+ break;
+ }
+ case 1:
+ {
+ srv_io_srv_conn_info_1("", &(ctr->conn.info1), ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s no connection info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_conn_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name ", ps, depth, &(q_n->ptr_srv_name));
+ smb_io_unistr2("", &(q_n->uni_srv_name), q_n->ptr_srv_name, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("ptr_qual_name", ps, depth, &(q_n->ptr_qual_name));
+ smb_io_unistr2("", &(q_n->uni_qual_name), q_n->ptr_qual_name, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("conn_level", ps, depth, &(q_n->conn_level ));
+
+ if (q_n->conn_level != -1)
+ {
+ srv_io_srv_conn_ctr("conn_ctr", q_n->ctr, ps, depth);
+ }
+
+ prs_uint32("preferred_len", ps, depth, &(q_n->preferred_len));
+
+ smb_io_enum_hnd("enum_hnd", &(q_n->enum_hnd), ps, depth);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_conn_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("conn_level", ps, depth, &(r_n->conn_level));
+
+ if (r_n->conn_level != -1)
+ {
+ srv_io_srv_conn_ctr("conn_ctr", r_n->ctr, ps, depth);
+ }
+
+ prs_uint32("total_entries", ps, depth, &(r_n->total_entries));
+ smb_io_enum_hnd("enum_hnd", &(r_n->enum_hnd), ps, depth);
+ prs_uint32("status ", ps, depth, &(r_n->status));
+}
+
+/*******************************************************************
+ makes a FILE_INFO_3_STR structure
+********************************************************************/
+void make_srv_file_info3_str(FILE_INFO_3_STR *fi3, char *user_name, char *path_name)
+{
+ if (fi3 == NULL) return;
+
+ DEBUG(5,("make_srv_file_info3_str\n"));
+
+ make_unistr2(&(fi3->uni_path_name), path_name, strlen(path_name)+1);
+ make_unistr2(&(fi3->uni_user_name), user_name, strlen(user_name)+1);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_file_info3_str(char *desc, FILE_INFO_3_STR *sh1, prs_struct *ps, int depth)
+{
+ if (sh1 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_file_info3_str");
+ depth++;
+
+ prs_align(ps);
+
+ smb_io_unistr2("", &(sh1->uni_path_name), True, ps, depth);
+ smb_io_unistr2("", &(sh1->uni_user_name), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a FILE_INFO_3 structure
+********************************************************************/
+void make_srv_file_info3(FILE_INFO_3 *fl3,
+ uint32 id, uint32 perms, uint32 num_locks,
+ char *path_name, char *user_name)
+{
+ if (fl3 == NULL) return;
+
+ DEBUG(5,("make_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 void srv_io_file_info3(char *desc, FILE_INFO_3 *fl3, prs_struct *ps, int depth)
+{
+ if (fl3 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_file_info3");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("id ", ps, depth, &(fl3->id ));
+ prs_uint32("perms ", ps, depth, &(fl3->perms ));
+ prs_uint32("num_locks ", ps, depth, &(fl3->num_locks ));
+ prs_uint32("ptr_path_name", ps, depth, &(fl3->ptr_path_name));
+ prs_uint32("ptr_user_name", ps, depth, &(fl3->ptr_user_name));
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_file_info_3(char *desc, SRV_FILE_INFO_3 *fl3, prs_struct *ps, int depth)
+{
+ if (fl3 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_file_3_fl3");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("num_entries_read", ps, depth, &(fl3->num_entries_read));
+ prs_uint32("ptr_file_fl3", ps, depth, &(fl3->ptr_file_info));
+ 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! */
+ }
+
+ prs_uint32("num_entries_read2", ps, depth, &(fl3->num_entries_read2));
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_file_info3("", &(fl3->info_3[i]), ps, depth);
+ }
+
+ for (i = 0; i < num_entries; i++)
+ {
+ prs_grow(ps);
+ srv_io_file_info3_str("", &(fl3->info_3_str[i]), ps, depth);
+ }
+
+ prs_align(ps);
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+static void srv_io_srv_file_ctr(char *desc, SRV_FILE_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_srv_file_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("switch_value", ps, depth, &(ctr->switch_value));
+ prs_uint32("ptr_file_ctr", ps, depth, &(ctr->ptr_file_ctr));
+
+ if (ctr->ptr_file_ctr != 0)
+ {
+ switch (ctr->switch_value)
+ {
+ case 3:
+ {
+ srv_io_srv_file_info_3("", &(ctr->file.info3), ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s no file info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_file_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name", ps, depth, &(q_n->ptr_srv_name));
+ smb_io_unistr2("", &(q_n->uni_srv_name), True, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("ptr_qual_name", ps, depth, &(q_n->ptr_qual_name));
+ smb_io_unistr2("", &(q_n->uni_qual_name), q_n->ptr_qual_name, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("file_level", ps, depth, &(q_n->file_level ));
+
+ if (q_n->file_level != -1)
+ {
+ srv_io_srv_file_ctr("file_ctr", q_n->ctr, ps, depth);
+ }
+
+ prs_uint32("preferred_len", ps, depth, &(q_n->preferred_len));
+
+ smb_io_enum_hnd("enum_hnd", &(q_n->enum_hnd), ps, depth);
+}
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_file_enum");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("file_level", ps, depth, &(r_n->file_level));
+
+ if (r_n->file_level != 0)
+ {
+ srv_io_srv_file_ctr("file_ctr", r_n->ctr, ps, depth);
+ }
+
+ prs_uint32("total_entries", ps, depth, &(r_n->total_entries));
+ smb_io_enum_hnd("enum_hnd", &(r_n->enum_hnd), ps, depth);
+ prs_uint32("status ", ps, depth, &(r_n->status));
+}
+
+/*******************************************************************
+ makes a SRV_INFO_101 structure.
+ ********************************************************************/
+void make_srv_info_101(SRV_INFO_101 *sv101, uint32 platform_id, char *name,
+ uint32 ver_major, uint32 ver_minor,
+ uint32 srv_type, char *comment)
+{
+ if (sv101 == NULL) return;
+
+ DEBUG(5,("make_srv_info_101\n"));
+
+ sv101->platform_id = platform_id;
+ make_buf_unistr2(&(sv101->uni_name ), &(sv101->ptr_name ) , name );
+ sv101->ver_major = ver_major;
+ sv101->ver_minor = ver_minor;
+ sv101->srv_type = srv_type;
+ make_buf_unistr2(&(sv101->uni_comment ), &(sv101->ptr_comment) , comment );
+}
+
+
+/*******************************************************************
+ reads or writes a SRV_INFO_101 structure.
+ ********************************************************************/
+static void srv_io_info_101(char *desc, SRV_INFO_101 *sv101, prs_struct *ps, int depth)
+{
+ if (sv101 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_info_101");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("platform_id ", ps, depth, &(sv101->platform_id ));
+ prs_uint32("ptr_name ", ps, depth, &(sv101->ptr_name ));
+ prs_uint32("ver_major ", ps, depth, &(sv101->ver_major ));
+ prs_uint32("ver_minor ", ps, depth, &(sv101->ver_minor ));
+ prs_uint32("srv_type ", ps, depth, &(sv101->srv_type ));
+ prs_uint32("ptr_comment ", ps, depth, &(sv101->ptr_comment ));
+
+ prs_align(ps);
+
+ smb_io_unistr2("uni_name ", &(sv101->uni_name ), True, ps, depth);
+ smb_io_unistr2("uni_comment ", &(sv101->uni_comment ), True, ps, depth);
+}
+
+/*******************************************************************
+ makes a SRV_INFO_102 structure.
+ ********************************************************************/
+void make_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)
+{
+ if (sv102 == NULL) return;
+
+ DEBUG(5,("make_srv_info_102\n"));
+
+ sv102->platform_id = platform_id;
+ make_buf_unistr2(&(sv102->uni_name ), &(sv102->ptr_name ), name );
+ sv102->ver_major = ver_major;
+ sv102->ver_minor = ver_minor;
+ sv102->srv_type = srv_type;
+ make_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;
+ make_buf_unistr2(&(sv102->uni_usr_path), &(sv102->ptr_usr_path), usr_path);
+}
+
+
+/*******************************************************************
+ reads or writes a SRV_INFO_102 structure.
+ ********************************************************************/
+static void srv_io_info_102(char *desc, SRV_INFO_102 *sv102, prs_struct *ps, int depth)
+{
+ if (sv102 == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_info102");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("platform_id ", ps, depth, &(sv102->platform_id ));
+ prs_uint32("ptr_name ", ps, depth, &(sv102->ptr_name ));
+ prs_uint32("ver_major ", ps, depth, &(sv102->ver_major ));
+ prs_uint32("ver_minor ", ps, depth, &(sv102->ver_minor ));
+ prs_uint32("srv_type ", ps, depth, &(sv102->srv_type ));
+ prs_uint32("ptr_comment ", ps, depth, &(sv102->ptr_comment ));
+
+ /* same as 101 up to here */
+
+ prs_uint32("users ", ps, depth, &(sv102->users ));
+ prs_uint32("disc ", ps, depth, &(sv102->disc ));
+ prs_uint32("hidden ", ps, depth, &(sv102->hidden ));
+ prs_uint32("announce ", ps, depth, &(sv102->announce ));
+ prs_uint32("ann_delta ", ps, depth, &(sv102->ann_delta ));
+ prs_uint32("licenses ", ps, depth, &(sv102->licenses ));
+ prs_uint32("ptr_usr_path", ps, depth, &(sv102->ptr_usr_path));
+
+ smb_io_unistr2("uni_name ", &(sv102->uni_name ), True, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_comment ", &(sv102->uni_comment ), True, ps, depth);
+ prs_align(ps);
+ smb_io_unistr2("uni_usr_path", &(sv102->uni_usr_path), True, ps, depth);
+}
+
+/*******************************************************************
+ reads or writes a SRV_INFO_102 structure.
+ ********************************************************************/
+static void srv_io_info_ctr(char *desc, SRV_INFO_CTR *ctr, prs_struct *ps, int depth)
+{
+ if (ctr == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_info_ctr");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("switch_value", ps, depth, &(ctr->switch_value));
+ prs_uint32("ptr_srv_ctr ", ps, depth, &(ctr->ptr_srv_ctr ));
+
+ if (ctr->ptr_srv_ctr != 0 && ctr->switch_value != 0 && ctr != NULL)
+ {
+ switch (ctr->switch_value)
+ {
+ case 101:
+ {
+ srv_io_info_101("sv101", &(ctr->srv.sv101), ps, depth);
+ break;
+ }
+ case 102:
+ {
+ srv_io_info_102("sv102", &(ctr->srv.sv102), ps, depth);
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("%s no server info at switch_value %d\n",
+ tab_depth(depth), ctr->switch_value));
+ break;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+reads or writes a structure.
+********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_srv_get_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name ", ps, depth, &(q_n->ptr_srv_name));
+ smb_io_unistr2("", &(q_n->uni_srv_name), True, ps, depth);
+
+ prs_align(ps);
+
+ prs_uint32("switch_value ", ps, depth, &(q_n->switch_value));
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_SRV_GET_INFO structure.
+ ********************************************************************/
+void make_srv_r_net_srv_get_info(SRV_R_NET_SRV_GET_INFO *srv,
+ uint32 switch_value, SRV_INFO_CTR *ctr, uint32 status)
+{
+ if (srv == NULL) return;
+
+ DEBUG(5,("make_srv_r_net_srv_get_info\n"));
+
+ srv->ctr = ctr;
+
+ if (status == 0x0)
+ {
+ 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;
+}
+
+/*******************************************************************
+ reads or writes a structure.
+ ********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_srv_get_info");
+ depth++;
+
+ prs_align(ps);
+
+ srv_io_info_ctr("ctr", r_n->ctr, ps, depth);
+
+ prs_uint32("status ", ps, depth, &(r_n->status ));
+}
+
+
+/*******************************************************************
+ reads or writes a structure.
+ ********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_q_net_remote_tod");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name ", ps, depth, &(q_n->ptr_srv_name));
+ smb_io_unistr2("", &(q_n->uni_srv_name), True, ps, depth);
+}
+
+/*******************************************************************
+ reads or writes a TIME_OF_DAY_INFO structure.
+ ********************************************************************/
+static void srv_io_time_of_day_info(char *desc, TIME_OF_DAY_INFO *tod, prs_struct *ps, int depth)
+{
+ if (tod == NULL) return;
+
+ prs_debug(ps, depth, desc, "srv_io_time_of_day_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("elapsedt ", ps, depth, &(tod->elapsedt ));
+ prs_uint32("msecs ", ps, depth, &(tod->msecs ));
+ prs_uint32("hours ", ps, depth, &(tod->hours ));
+ prs_uint32("mins ", ps, depth, &(tod->mins ));
+ prs_uint32("secs ", ps, depth, &(tod->secs ));
+ prs_uint32("hunds ", ps, depth, &(tod->hunds ));
+ prs_uint32("timezone ", ps, depth, &(tod->zone ));
+ prs_uint32("tintervals ", ps, depth, &(tod->tintervals));
+ prs_uint32("day ", ps, depth, &(tod->day ));
+ prs_uint32("month ", ps, depth, &(tod->month ));
+ prs_uint32("year ", ps, depth, &(tod->year ));
+ prs_uint32("weekday ", ps, depth, &(tod->weekday ));
+
+}
+
+/*******************************************************************
+ makes a TIME_OF_DAY_INFO structure.
+ ********************************************************************/
+void make_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)
+{
+ if (tod == NULL) return;
+
+ DEBUG(5,("make_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.
+ ********************************************************************/
+void 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;
+
+ prs_debug(ps, depth, desc, "srv_io_r_net_remote_tod");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_tod ", ps, depth, &(r_n->ptr_srv_tod));
+
+ srv_io_time_of_day_info("tod", r_n->tod, ps, depth);
+
+ prs_uint32("status ", ps, depth, &(r_n->status));
+}
diff --git a/source/rpc_parse/parse_wks.c b/source/rpc_parse/parse_wks.c
new file mode 100644
index 00000000000..2386fa66368
--- /dev/null
+++ b/source/rpc_parse/parse_wks.c
@@ -0,0 +1,145 @@
+
+/*
+ * 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"
+
+extern int DEBUGLEVEL;
+
+/*******************************************************************
+ make_wks_q_query_info
+ ********************************************************************/
+void make_wks_q_query_info(WKS_Q_QUERY_INFO *q_u,
+ char *server, uint16 switch_value)
+{
+ DEBUG(5,("make_wks_q_query_info\n"));
+
+ make_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.
+********************************************************************/
+void wks_io_q_query_info(char *desc, WKS_Q_QUERY_INFO *q_u, prs_struct *ps, int depth)
+{
+ if (q_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "wks_io_q_query_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("ptr_srv_name", ps, depth, &(q_u->ptr_srv_name));
+ smb_io_unistr2("", &(q_u->uni_srv_name), q_u->ptr_srv_name, ps, depth);
+ prs_align(ps);
+
+ prs_uint16("switch_value", ps, depth, &(q_u->switch_value));
+ prs_align(ps);
+}
+
+/*******************************************************************
+ wks_info_100
+ ********************************************************************/
+void make_wks_info_100(WKS_INFO_100 *inf,
+ uint32 platform_id, uint32 ver_major, uint32 ver_minor,
+ char *my_name, char *domain_name)
+{
+ DEBUG(5,("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 */
+
+ make_buf_unistr2(&(inf->uni_compname), &(inf->ptr_compname), my_name );
+ make_buf_unistr2(&(inf->uni_lan_grp ), &(inf->ptr_lan_grp ), domain_name);
+}
+
+/*******************************************************************
+reads or writes a WKS_INFO_100 structure.
+********************************************************************/
+static void wks_io_wks_info_100(char *desc, WKS_INFO_100 *inf, prs_struct *ps, int depth)
+{
+ if (inf == NULL) return;
+
+ prs_debug(ps, depth, desc, "wks_io_wks_info_100");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint32("platform_id ", ps, depth, &(inf->platform_id )); /* 0x0000 01f4 - unknown */
+ prs_uint32("ptr_compname", ps, depth, &(inf->ptr_compname)); /* pointer to computer name */
+ prs_uint32("ptr_lan_grp ", ps, depth, &(inf->ptr_lan_grp )); /* pointer to LAN group name */
+ prs_uint32("ver_major ", ps, depth, &(inf->ver_major )); /* 4 - major os version */
+ prs_uint32("ver_minor ", ps, depth, &(inf->ver_minor )); /* 0 - minor os version */
+
+ smb_io_unistr2("", &(inf->uni_compname), inf->ptr_compname, ps, depth);
+ prs_align(ps);
+
+ smb_io_unistr2("", &(inf->uni_lan_grp ), inf->ptr_lan_grp , ps, depth);
+ prs_align(ps);
+}
+
+/*******************************************************************
+ make_wks_r_query_info
+
+ only supports info level 100 at the moment.
+
+ ********************************************************************/
+void make_wks_r_query_info(WKS_R_QUERY_INFO *r_u,
+ uint32 switch_value, WKS_INFO_100 *wks100,
+ int status)
+{
+ DEBUG(5,("make_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.
+********************************************************************/
+void wks_io_r_query_info(char *desc, WKS_R_QUERY_INFO *r_u, prs_struct *ps, int depth)
+{
+ if (r_u == NULL) return;
+
+ prs_debug(ps, depth, desc, "wks_io_r_query_info");
+ depth++;
+
+ prs_align(ps);
+
+ prs_uint16("switch_value", ps, depth, &(r_u->switch_value)); /* level 100 (0x64) */
+ prs_align(ps);
+
+ prs_uint32("ptr_1 ", ps, depth, &(r_u->ptr_1 )); /* pointer 1 */
+ wks_io_wks_info_100("inf", r_u->wks100, ps, depth);
+
+ prs_uint32("status ", ps, depth, &(r_u->status));
+}
+
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_ldap_helpers.c b/source/rpc_server/srv_ldap_helpers.c
new file mode 100644
index 00000000000..fb2442789c8
--- /dev/null
+++ b/source/rpc_server/srv_ldap_helpers.c
@@ -0,0 +1,14 @@
+#ifdef USE_LDAP
+
+#include "includes.h"
+#include "lber.h"
+#include "ldap.h"
+
+extern int DEBUGLEVEL;
+
+
+#else /* USE_LDAP */
+/* this keeps fussy compilers happy */
+void ldap_helper_dummy(void)
+{}
+#endif /* USE_LDAP */
diff --git a/source/rpc_server/srv_lsa.c b/source/rpc_server/srv_lsa.c
new file mode 100644
index 00000000000..35ceeace04f
--- /dev/null
+++ b/source/rpc_server/srv_lsa.c
@@ -0,0 +1,497 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern DOM_SID global_machine_sid;
+
+/***************************************************************************
+lsa_reply_open_policy
+ ***************************************************************************/
+static void lsa_reply_open_policy(prs_struct *rdata)
+{
+ int i;
+ LSA_R_OPEN_POL r_o;
+
+ ZERO_STRUCT(r_o);
+
+ /* set up the LSA QUERY INFO response */
+
+ for (i = 4; i < POL_HND_SIZE; i++)
+ {
+ r_o.pol.data[i] = i;
+ }
+ r_o.status = 0x0;
+
+ /* store the response in the SMB stream */
+ lsa_io_r_open_pol("", &r_o, rdata, 0);
+}
+
+/***************************************************************************
+make_dom_query
+ ***************************************************************************/
+static void make_dom_query(DOM_QUERY *d_q, char *dom_name, DOM_SID *dom_sid)
+{
+ int domlen = strlen(dom_name);
+
+ d_q->uni_dom_max_len = domlen * 2;
+ d_q->uni_dom_str_len = domlen * 2;
+
+ d_q->buffer_dom_name = 4; /* domain buffer pointer */
+ d_q->buffer_dom_sid = 2; /* domain sid pointer */
+
+ /* this string is supposed to be character short */
+ make_unistr2(&(d_q->uni_domain_name), dom_name, domlen);
+
+ make_dom_sid2(&(d_q->dom_sid), dom_sid);
+}
+
+/***************************************************************************
+lsa_reply_query_info
+ ***************************************************************************/
+static void lsa_reply_enum_trust_dom(LSA_Q_ENUM_TRUST_DOM *q_e,
+ prs_struct *rdata,
+ uint32 enum_context, char *dom_name, DOM_SID *dom_sid)
+{
+ LSA_R_ENUM_TRUST_DOM r_e;
+
+ ZERO_STRUCT(r_e);
+
+ /* set up the LSA QUERY INFO response */
+ make_r_enum_trust_dom(&r_e, enum_context, dom_name, dom_sid,
+ dom_name != NULL ? 0x0 : 0x80000000 | NT_STATUS_UNABLE_TO_FREE_VM);
+
+ /* store the response in the SMB stream */
+ lsa_io_r_enum_trust_dom("", &r_e, rdata, 0);
+}
+
+/***************************************************************************
+lsa_reply_query_info
+ ***************************************************************************/
+static void lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, prs_struct *rdata,
+ char *dom_name, DOM_SID *dom_sid)
+{
+ LSA_R_QUERY_INFO r_q;
+
+ ZERO_STRUCT(r_q);
+
+ /* set up the LSA QUERY INFO response */
+
+ r_q.undoc_buffer = 0x22000000; /* bizarre */
+ r_q.info_class = q_q->info_class;
+
+ make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
+
+ r_q.status = 0x0;
+
+ /* store the response in the SMB stream */
+ lsa_io_r_query("", &r_q, rdata, 0);
+}
+
+/***************************************************************************
+make_dom_ref
+
+ pretty much hard-coded choice of "other" sids, unfortunately...
+
+ ***************************************************************************/
+static void make_dom_ref(DOM_R_REF *ref, char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ int len_dom_name = strlen(dom_name);
+
+ ref->undoc_buffer = 1;
+ ref->num_ref_doms_1 = 4;
+ ref->buffer_dom_name = 1;
+ ref->max_entries = 32;
+ ref->num_ref_doms_2 = 4;
+
+ make_uni_hdr2(&(ref->hdr_dom_name ), len_dom_name , len_dom_name , 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[0]), sizeof(DOM_SID), sizeof(DOM_SID), 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[1]), sizeof(DOM_SID), sizeof(DOM_SID), 0);
+ make_uni_hdr2(&(ref->hdr_ref_dom[2]), sizeof(DOM_SID), sizeof(DOM_SID), 0);
+
+ if (dom_name != NULL)
+ {
+ make_unistr(&(ref->uni_dom_name), dom_name);
+ }
+
+ make_dom_sid2(&(ref->ref_dom[0]), dom_sid );
+ make_dom_sid2(&(ref->ref_dom[1]), other_sid1);
+ make_dom_sid2(&(ref->ref_dom[2]), other_sid2);
+ make_dom_sid2(&(ref->ref_dom[3]), other_sid3);
+}
+
+/***************************************************************************
+make_reply_lookup_rids
+ ***************************************************************************/
+static void make_reply_lookup_rids(LSA_R_LOOKUP_RIDS *r_l,
+ int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
+ char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ int i;
+
+ make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
+ other_sid1, other_sid2, other_sid3);
+
+ r_l->num_entries = num_entries;
+ r_l->undoc_buffer = 1;
+ r_l->num_entries2 = num_entries;
+
+ SMB_ASSERT_ARRAY(r_l->dom_rid, num_entries);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ make_dom_rid2(&(r_l->dom_rid[i]), dom_rids[i]);
+ }
+
+ r_l->num_entries3 = num_entries;
+}
+
+/***************************************************************************
+make_lsa_trans_names
+ ***************************************************************************/
+static void make_lsa_trans_names(LSA_TRANS_NAME_ENUM *trn,
+ int num_entries, DOM_SID2 sid[MAX_LOOKUP_SIDS],
+ uint32 *total)
+{
+ uint32 status = 0x0;
+ int i;
+ (*total) = 0;
+
+ SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS);
+
+ for (i = 0; i < num_entries; i++)
+ {
+ uint32 rid = 0xffffffff;
+ uint8 num_auths = sid[i].sid.num_auths;
+ fstring name;
+ uint32 type;
+
+ trn->ptr_name[i] = 0;
+ trn->ptr_name[(*total)] = 0;
+
+ SMB_ASSERT_ARRAY(sid[i].sid.sub_auths, num_auths);
+
+ /* find the rid to look up */
+ if (num_auths != 0)
+ {
+ rid = sid[i].sid.sub_auths[num_auths-1];
+
+ status = 0xC0000000 | NT_STATUS_NONE_MAPPED;
+
+ status = (status != 0x0) ? lookup_user_name (rid, name, &type) : status;
+ status = (status != 0x0) ? lookup_group_name(rid, name, &type) : status;
+ status = (status != 0x0) ? lookup_alias_name(rid, name, &type) : status;
+ }
+
+ if (status == 0x0)
+ {
+ trn->ptr_name[i] = 1;
+ make_lsa_trans_name(&(trn->name[(*total)]), type, name, (*total));
+ (*total)++;
+ }
+ }
+
+ trn->num_entries = (*total);
+ trn->ptr_trans_names = 1;
+ trn->num_entries2 = (*total);
+}
+
+/***************************************************************************
+make_reply_lookup_sids
+ ***************************************************************************/
+static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
+ DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *names,
+ uint32 mapped_count, uint32 status)
+{
+ r_l->dom_ref = ref;
+ r_l->names = names;
+ r_l->mapped_count = mapped_count;
+ r_l->status = status;
+}
+
+/***************************************************************************
+lsa_reply_lookup_sids
+ ***************************************************************************/
+static void lsa_reply_lookup_sids(prs_struct *rdata,
+ int num_entries, DOM_SID2 sid[MAX_LOOKUP_SIDS],
+ char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ LSA_R_LOOKUP_SIDS r_l;
+ DOM_R_REF ref;
+ LSA_TRANS_NAME_ENUM names;
+ uint32 mapped_count = 0;
+
+ ZERO_STRUCT(r_l);
+ ZERO_STRUCT(ref);
+ ZERO_STRUCT(names);
+
+ /* set up the LSA Lookup SIDs response */
+ make_dom_ref(&ref, dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
+ make_lsa_trans_names(&names, num_entries, sid, &mapped_count);
+ make_reply_lookup_sids(&r_l, &ref, &names, mapped_count, 0x0);
+
+ /* store the response in the SMB stream */
+ lsa_io_r_lookup_sids("", &r_l, rdata, 0);
+}
+
+/***************************************************************************
+lsa_reply_lookup_rids
+ ***************************************************************************/
+static void lsa_reply_lookup_rids(prs_struct *rdata,
+ int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
+ char *dom_name, DOM_SID *dom_sid,
+ DOM_SID *other_sid1, DOM_SID *other_sid2, DOM_SID *other_sid3)
+{
+ LSA_R_LOOKUP_RIDS r_l;
+
+ ZERO_STRUCT(r_l);
+
+ /* set up the LSA Lookup RIDs response */
+ make_reply_lookup_rids(&r_l, num_entries, dom_rids,
+ dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
+ r_l.status = 0x0;
+
+ /* store the response in the SMB stream */
+ lsa_io_r_lookup_rids("", &r_l, rdata, 0);
+}
+
+/***************************************************************************
+api_lsa_open_policy
+ ***************************************************************************/
+static void api_lsa_open_policy( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_OPEN_POL q_o;
+
+ ZERO_STRUCT(q_o);
+
+ /* grab the server, object attributes and desired access flag...*/
+ lsa_io_q_open_pol("", &q_o, data, 0);
+
+ /* lkclXXXX having decoded it, ignore all fields in the open policy! */
+
+ /* return a 20 byte policy handle */
+ lsa_reply_open_policy(rdata);
+}
+
+/***************************************************************************
+api_lsa_enum_trust_dom
+ ***************************************************************************/
+static void api_lsa_enum_trust_dom( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_ENUM_TRUST_DOM q_e;
+
+ ZERO_STRUCT(q_e);
+
+ /* grab the enum trust domain context etc. */
+ lsa_io_q_enum_trust_dom("", &q_e, data, 0);
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_enum_trust_dom(&q_e, rdata,
+ 0, NULL, NULL);
+}
+
+/***************************************************************************
+api_lsa_query_info
+ ***************************************************************************/
+static void api_lsa_query_info( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_QUERY_INFO q_i;
+ pstring dom_name;
+
+ ZERO_STRUCT(q_i);
+
+ /* grab the info class and policy handle */
+ lsa_io_q_query("", &q_i, data, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_query_info(&q_i, rdata, dom_name, &global_machine_sid);
+}
+
+/***************************************************************************
+api_lsa_lookup_sids
+ ***************************************************************************/
+static void api_lsa_lookup_sids( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ LSA_Q_LOOKUP_SIDS q_l;
+ pstring dom_name;
+ DOM_SID sid_S_1_1;
+ DOM_SID sid_S_1_3;
+ DOM_SID sid_S_1_5;
+
+ ZERO_STRUCT(q_l);
+ ZERO_STRUCT(sid_S_1_1);
+ ZERO_STRUCT(sid_S_1_3);
+ ZERO_STRUCT(sid_S_1_5);
+
+ /* grab the info class and policy handle */
+ lsa_io_q_lookup_sids("", &q_l, data, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+
+ string_to_sid(&sid_S_1_1, "S-1-1");
+ string_to_sid(&sid_S_1_3, "S-1-3");
+ string_to_sid(&sid_S_1_5, "S-1-5");
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_lookup_sids(rdata,
+ q_l.sids.num_entries, q_l.sids.sid, /* SIDs */
+ dom_name, &global_machine_sid, /* domain name, domain SID */
+ &sid_S_1_1, &sid_S_1_3, &sid_S_1_5); /* the three other SIDs */
+}
+
+/***************************************************************************
+api_lsa_lookup_names
+ ***************************************************************************/
+static void api_lsa_lookup_names( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ int i;
+ LSA_Q_LOOKUP_RIDS q_l;
+ pstring dom_name;
+ DOM_SID sid_S_1_1;
+ DOM_SID sid_S_1_3;
+ DOM_SID sid_S_1_5;
+ uint32 dom_rids[MAX_LOOKUP_SIDS];
+ uint32 dummy_g_rid;
+
+ ZERO_STRUCT(q_l);
+ ZERO_STRUCT(sid_S_1_1);
+ ZERO_STRUCT(sid_S_1_3);
+ ZERO_STRUCT(sid_S_1_5);
+ ZERO_ARRAY(dom_rids);
+
+ /* grab the info class and policy handle */
+ lsa_io_q_lookup_rids("", &q_l, data, 0);
+
+ pstrcpy(dom_name, lp_workgroup());
+
+ string_to_sid(&sid_S_1_1, "S-1-1");
+ string_to_sid(&sid_S_1_3, "S-1-3");
+ string_to_sid(&sid_S_1_5, "S-1-5");
+
+ SMB_ASSERT_ARRAY(q_l.lookup_name, q_l.num_entries);
+
+ /* convert received RIDs to strings, so we can do them. */
+ for (i = 0; i < q_l.num_entries; i++)
+ {
+ fstring user_name;
+ fstrcpy(user_name, unistr2(q_l.lookup_name[i].str.buffer));
+ /*
+ * Map to the UNIX username.
+ */
+ map_username(user_name);
+
+ /*
+ * Do any case conversions.
+ */
+ (void)Get_Pwnam(user_name, True);
+
+ if (!pdb_name_to_rid(user_name, &dom_rids[i], &dummy_g_rid))
+ {
+ /* WHOOPS! we should really do something about this... */
+ dom_rids[i] = 0;
+ }
+ }
+
+ /* construct reply. return status is always 0x0 */
+ lsa_reply_lookup_rids(rdata,
+ q_l.num_entries, dom_rids, /* text-converted SIDs */
+ dom_name, &global_machine_sid, /* domain name, domain SID */
+ &sid_S_1_1, &sid_S_1_3, &sid_S_1_5); /* the three other SIDs */
+}
+
+/***************************************************************************
+ api_lsa_close
+ ***************************************************************************/
+static void api_lsa_close( int uid, prs_struct *data,
+ prs_struct *rdata)
+{
+ /* XXXX this is NOT good */
+ char *q = mem_data(&(rdata->data), rdata->offset);
+
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+
+ rdata->offset += 24;
+}
+
+/***************************************************************************
+ api_lsa_open_secret
+ ***************************************************************************/
+static void api_lsa_open_secret( int uid, prs_struct *data,
+ prs_struct *rdata)
+{
+ /* XXXX this is NOT good */
+ char *q = mem_data(&(rdata->data), rdata->offset);
+
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0); q += 4;
+ SIVAL(q, 0, 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND); q += 4;
+
+ rdata->offset += 24;
+}
+
+/***************************************************************************
+ \PIPE\ntlsa commands
+ ***************************************************************************/
+static struct api_struct api_lsa_cmds[] =
+{
+ { "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 },
+ { NULL , 0 , NULL }
+};
+
+/***************************************************************************
+ api_ntLsarpcTNP
+ ***************************************************************************/
+BOOL api_ntlsa_rpc(pipes_struct *p, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_ntlsa_rpc", api_lsa_cmds, data);
+}
+
diff --git a/source/rpc_server/srv_lsa_hnd.c b/source/rpc_server/srv_lsa_hnd.c
new file mode 100644
index 00000000000..b1e695360f7
--- /dev/null
+++ b/source/rpc_server/srv_lsa_hnd.c
@@ -0,0 +1,289 @@
+
+/*
+ * 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,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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 DEBUGLEVEL;
+
+#ifndef MAX_OPEN_POLS
+#define MAX_OPEN_POLS 64
+#endif
+
+struct reg_info
+{
+ /* for use by \PIPE\winreg */
+ fstring name; /* name of registry key */
+};
+
+struct samr_info
+{
+ /* for use by the \PIPE\samr policy */
+ DOM_SID sid;
+ uint32 rid; /* relative id associated with the pol_hnd */
+ uint32 status; /* some sort of flag. best to record it. comes from opnum 0x39 */
+};
+
+static struct policy
+{
+ struct policy *next, *prev;
+ int pnum;
+ BOOL open;
+ POLICY_HND pol_hnd;
+
+ union {
+ struct samr_info samr;
+ struct reg_info reg;
+ } dev;
+} *Policy;
+
+static struct bitmap *bmap;
+
+
+/****************************************************************************
+ create a unique policy handle
+****************************************************************************/
+static void create_pol_hnd(POLICY_HND *hnd)
+{
+ static uint32 pol_hnd_low = 0;
+ static uint32 pol_hnd_high = 0;
+
+ if (hnd == NULL) return;
+
+ /* i severely doubt that pol_hnd_high will ever be non-zero... */
+ pol_hnd_low++;
+ if (pol_hnd_low == 0) pol_hnd_high++;
+
+ SIVAL(hnd->data, 0 , 0x0); /* first bit must be null */
+ SIVAL(hnd->data, 4 , pol_hnd_low ); /* second bit is incrementing */
+ SIVAL(hnd->data, 8 , pol_hnd_high); /* second bit is incrementing */
+ SIVAL(hnd->data, 12, time(NULL)); /* something random */
+ SIVAL(hnd->data, 16, getpid()); /* something more random */
+}
+
+/****************************************************************************
+ initialise policy handle states...
+****************************************************************************/
+void init_lsa_policy_hnd(void)
+{
+ bmap = bitmap_allocate(MAX_OPEN_POLS);
+ if (!bmap) {
+ exit_server("out of memory in init_lsa_policy_hnd\n");
+ }
+}
+
+/****************************************************************************
+ find first available policy slot. creates a policy handle for you.
+****************************************************************************/
+BOOL open_lsa_policy_hnd(POLICY_HND *hnd)
+{
+ int i;
+ struct policy *p;
+
+ i = bitmap_find(bmap, 1);
+
+ if (i == -1) {
+ DEBUG(0,("ERROR: out of Policy Handles!\n"));
+ return False;
+ }
+
+ p = (struct policy *)malloc(sizeof(*p));
+ if (!p) {
+ DEBUG(0,("ERROR: out of memory!\n"));
+ return False;
+ }
+
+ ZERO_STRUCTP(p);
+
+ p->open = True;
+ p->pnum = i;
+
+ create_pol_hnd(hnd);
+ memcpy(&p->pol_hnd, hnd, sizeof(*hnd));
+
+ bitmap_set(bmap, i);
+
+ DLIST_ADD(Policy, p);
+
+ DEBUG(4,("Opened policy hnd[%x] ", i));
+ dump_data(4, (char *)hnd->data, sizeof(hnd->data));
+
+ return True;
+}
+
+/****************************************************************************
+ find policy by handle
+****************************************************************************/
+static struct policy *find_lsa_policy(POLICY_HND *hnd)
+{
+ struct policy *p;
+
+ for (p=Policy;p;p=p->next) {
+ if (memcmp(&p->pol_hnd, hnd, sizeof(*hnd)) == 0) {
+ DEBUG(4,("Found policy hnd[%x] ", p->pnum));
+ dump_data(4, (char *)hnd->data, sizeof(hnd->data));
+ return p;
+ }
+ }
+
+ DEBUG(4,("Policy not found: "));
+ dump_data(4, (char *)hnd->data, sizeof(hnd->data));
+
+ return NULL;
+}
+
+/****************************************************************************
+ find policy index by handle
+****************************************************************************/
+int find_lsa_policy_by_hnd(POLICY_HND *hnd)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ return p?p->pnum:-1;
+}
+
+/****************************************************************************
+ set samr rid
+****************************************************************************/
+BOOL set_lsa_policy_samr_rid(POLICY_HND *hnd, uint32 rid)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy device rid=%x pnum=%x\n",
+ rid, p->pnum));
+
+ p->dev.samr.rid = rid;
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy rid=%x\n",rid));
+ return False;
+}
+
+
+/****************************************************************************
+ set samr pol status. absolutely no idea what this is.
+****************************************************************************/
+BOOL set_lsa_policy_samr_pol_status(POLICY_HND *hnd, uint32 pol_status)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy status=%x pnum=%x\n",
+ pol_status, p->pnum));
+
+ p->dev.samr.status = pol_status;
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy status=%x\n",
+ pol_status));
+ return False;
+}
+
+/****************************************************************************
+ set samr sid
+****************************************************************************/
+BOOL set_lsa_policy_samr_sid(POLICY_HND *hnd, DOM_SID *sid)
+{
+ pstring sidstr;
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy sid=%s pnum=%x\n",
+ sid_to_string(sidstr, sid), p->pnum));
+
+ memcpy(&p->dev.samr.sid, sid, sizeof(*sid));
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy sid=%s\n",
+ sid_to_string(sidstr, sid)));
+ return False;
+}
+
+/****************************************************************************
+ set samr rid
+****************************************************************************/
+uint32 get_lsa_policy_samr_rid(POLICY_HND *hnd)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ uint32 rid = p->dev.samr.rid;
+ DEBUG(3,("Getting policy device rid=%x pnum=%x\n",
+ rid, p->pnum));
+
+ return rid;
+ }
+
+ DEBUG(3,("Error getting policy\n"));
+ return 0xffffffff;
+}
+
+/****************************************************************************
+ set reg name
+****************************************************************************/
+BOOL set_lsa_policy_reg_name(POLICY_HND *hnd, fstring name)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (p && p->open) {
+ DEBUG(3,("Setting policy pnum=%x name=%s\n",
+ p->pnum, name));
+
+ fstrcpy(p->dev.reg.name, name);
+ return True;
+ }
+
+ DEBUG(3,("Error setting policy name=%s\n", name));
+ return False;
+}
+
+/****************************************************************************
+ close an lsa policy
+****************************************************************************/
+BOOL close_lsa_policy_hnd(POLICY_HND *hnd)
+{
+ struct policy *p = find_lsa_policy(hnd);
+
+ if (!p) {
+ DEBUG(3,("Error closing policy\n"));
+ return False;
+ }
+
+ DEBUG(3,("Closed policy name pnum=%x\n", p->pnum));
+
+ DLIST_REMOVE(Policy, p);
+
+ bitmap_clear(bmap, p->pnum);
+
+ ZERO_STRUCTP(p);
+
+ free(p);
+
+ return True;
+}
+
diff --git a/source/rpc_server/srv_netlog.c b/source/rpc_server/srv_netlog.c
new file mode 100644
index 00000000000..cb22cfddf02
--- /dev/null
+++ b/source/rpc_server/srv_netlog.c
@@ -0,0 +1,875 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+extern BOOL sam_logon_in_ssb;
+extern pstring samlogon_user;
+extern pstring global_myname;
+extern DOM_SID global_machine_sid;
+
+/*************************************************************************
+ make_net_r_req_chal:
+ *************************************************************************/
+static void make_net_r_req_chal(NET_R_REQ_CHAL *r_c,
+ DOM_CHAL *srv_chal, int status)
+{
+ DEBUG(6,("make_net_r_req_chal: %d\n", __LINE__));
+ memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
+ r_c->status = status;
+}
+
+/*************************************************************************
+ net_reply_req_chal:
+ *************************************************************************/
+static void net_reply_req_chal(NET_Q_REQ_CHAL *q_c, prs_struct *rdata,
+ DOM_CHAL *srv_chal, uint32 srv_time)
+{
+ NET_R_REQ_CHAL r_c;
+
+ DEBUG(6,("net_reply_req_chal: %d\n", __LINE__));
+
+ /* set up the LSA REQUEST CHALLENGE response */
+ make_net_r_req_chal(&r_c, srv_chal, srv_time);
+
+ /* store the response in the SMB stream */
+ net_io_r_req_chal("", &r_c, rdata, 0);
+
+ DEBUG(6,("net_reply_req_chal: %d\n", __LINE__));
+
+}
+
+/*************************************************************************
+ net_reply_logon_ctrl2:
+ *************************************************************************/
+static void net_reply_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, prs_struct *rdata,
+ uint32 flags, uint32 pdc_status, uint32 logon_attempts,
+ uint32 tc_status, char *trust_domain_name)
+{
+ NET_R_LOGON_CTRL2 r_l;
+
+ DEBUG(6,("net_reply_logon_ctrl2: %d\n", __LINE__));
+
+ /* set up the Logon Control2 response */
+ make_r_logon_ctrl2(&r_l, q_l->query_level,
+ flags, pdc_status, logon_attempts,
+ tc_status, trust_domain_name);
+
+ /* store the response in the SMB stream */
+ net_io_r_logon_ctrl2("", &r_l, rdata, 0);
+
+ DEBUG(6,("net_reply_logon_ctrl2: %d\n", __LINE__));
+
+}
+
+/*************************************************************************
+ net_reply_trust_dom_list:
+ *************************************************************************/
+static void net_reply_trust_dom_list(NET_Q_TRUST_DOM_LIST *q_t, prs_struct *rdata,
+ uint32 num_trust_domains, char *trust_domain_name)
+{
+ NET_R_TRUST_DOM_LIST r_t;
+
+ DEBUG(6,("net_reply_trust_dom_list: %d\n", __LINE__));
+
+ /* set up the Trusted Domain List response */
+ make_r_trust_dom(&r_t, num_trust_domains, trust_domain_name);
+
+ /* store the response in the SMB stream */
+ net_io_r_trust_dom("", &r_t, rdata, 0);
+
+ DEBUG(6,("net_reply_trust_dom_listlogon_ctrl2: %d\n", __LINE__));
+
+}
+
+/*************************************************************************
+ make_net_r_auth_2:
+ *************************************************************************/
+static void make_net_r_auth_2(NET_R_AUTH_2 *r_a,
+ DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int 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_reply_auth_2:
+ *************************************************************************/
+static void net_reply_auth_2(NET_Q_AUTH_2 *q_a, prs_struct *rdata,
+ DOM_CHAL *resp_cred, int status)
+{
+ NET_R_AUTH_2 r_a;
+
+ /* set up the LSA AUTH 2 response */
+
+ make_net_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
+
+ /* store the response in the SMB stream */
+ net_io_r_auth_2("", &r_a, rdata, 0);
+
+}
+
+/***********************************************************************************
+ make_net_r_srv_pwset:
+ ***********************************************************************************/
+static void make_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
+ DOM_CRED *srv_cred, int status)
+{
+ DEBUG(5,("make_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,("make_net_r_srv_pwset: %d\n", __LINE__));
+}
+
+/*************************************************************************
+ net_reply_srv_pwset:
+ *************************************************************************/
+static void net_reply_srv_pwset(NET_Q_SRV_PWSET *q_s, prs_struct *rdata,
+ DOM_CRED *srv_cred, int status)
+{
+ NET_R_SRV_PWSET r_s;
+
+ DEBUG(5,("net_srv_pwset: %d\n", __LINE__));
+
+ /* set up the LSA Server Password Set response */
+ make_net_r_srv_pwset(&r_s, srv_cred, status);
+
+ /* store the response in the SMB stream */
+ net_io_r_srv_pwset("", &r_s, rdata, 0);
+
+ DEBUG(5,("net_srv_pwset: %d\n", __LINE__));
+
+}
+
+/*************************************************************************
+ net_reply_sam_logon:
+ *************************************************************************/
+static void net_reply_sam_logon(NET_Q_SAM_LOGON *q_s, prs_struct *rdata,
+ DOM_CRED *srv_cred, NET_USER_INFO_3 *user_info,
+ uint32 status)
+{
+ NET_R_SAM_LOGON r_s;
+
+ /* XXXX maybe we want to say 'no', reject the client's credentials */
+ r_s.buffer_creds = 1; /* yes, we have valid server credentials */
+ memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
+
+ /* store the user information, if there is any. */
+ r_s.user = user_info;
+ if (status == 0x0 && user_info != NULL && user_info->ptr_user_info != 0)
+ {
+ r_s.switch_value = 3; /* indicates type of validation user info */
+ }
+ else
+ {
+ r_s.switch_value = 0; /* indicates no info */
+ }
+
+ r_s.status = status;
+ r_s.auth_resp = 1; /* authoritative response */
+
+ /* store the response in the SMB stream */
+ net_io_r_sam_logon("", &r_s, rdata, 0);
+
+}
+
+
+/*************************************************************************
+ net_reply_sam_logoff:
+ *************************************************************************/
+static void net_reply_sam_logoff(NET_Q_SAM_LOGOFF *q_s, prs_struct *rdata,
+ DOM_CRED *srv_cred,
+ uint32 status)
+{
+ NET_R_SAM_LOGOFF r_s;
+
+ /* XXXX maybe we want to say 'no', reject the client's credentials */
+ r_s.buffer_creds = 1; /* yes, we have valid server credentials */
+ memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
+
+ r_s.status = status;
+
+ /* store the response in the SMB stream */
+ net_io_r_sam_logoff("", &r_s, rdata, 0);
+
+}
+
+/******************************************************************
+ gets a machine password entry. checks access rights of the host.
+ ******************************************************************/
+static BOOL get_md4pw(char *md4pw, char *mach_name, char *mach_acct)
+{
+ struct smb_passwd *smb_pass;
+
+#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), client_addr(Client)))
+ {
+ DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
+ return False;
+ }
+#endif /* 0 */
+
+ become_root(True);
+ smb_pass = getsmbpwnam(mach_acct);
+ unbecome_root(True);
+
+ if ((smb_pass) != NULL && !(smb_pass->acct_ctrl & ACB_DISABLED) &&
+ (smb_pass->smb_nt_passwd != NULL))
+ {
+ memcpy(md4pw, smb_pass->smb_nt_passwd, 16);
+ dump_data(5, md4pw, 16);
+
+ return True;
+ }
+ DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
+ return False;
+}
+
+/*************************************************************************
+ api_net_req_chal:
+ *************************************************************************/
+static void api_net_req_chal( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_REQ_CHAL q_r;
+ uint32 status = 0x0;
+
+ fstring mach_acct;
+ fstring mach_name;
+
+ user_struct *vuser;
+
+ DEBUG(5,("api_net_req_chal(%d): vuid %d\n", __LINE__, uid));
+
+ if ((vuser = get_valid_user_struct(uid)) == NULL) return;
+
+ /* grab the challenge... */
+ net_io_q_req_chal("", &q_r, data, 0);
+
+ fstrcpy(mach_acct, unistrn2(q_r.uni_logon_clnt.buffer,
+ q_r.uni_logon_clnt.uni_str_len));
+
+ fstrcpy(mach_name, mach_acct);
+ strlower(mach_name);
+
+ fstrcat(mach_acct, "$");
+
+ if (get_md4pw((char *)vuser->dc.md4pw, mach_name, mach_acct))
+ {
+ /* copy the client credentials */
+ memcpy(vuser->dc.clnt_chal.data , q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
+ memcpy(vuser->dc.clnt_cred.challenge.data, q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
+
+ /* create a server challenge for the client */
+ /* Set these to random values. */
+ generate_random_buffer(vuser->dc.srv_chal.data, 8, False);
+
+ memcpy(vuser->dc.srv_cred.challenge.data, vuser->dc.srv_chal.data, 8);
+
+ bzero(vuser->dc.sess_key, sizeof(vuser->dc.sess_key));
+
+ /* from client / server challenges and md4 password, generate sess key */
+ cred_session_key(&(vuser->dc.clnt_chal), &(vuser->dc.srv_chal),
+ (char *)vuser->dc.md4pw, vuser->dc.sess_key);
+ }
+ else
+ {
+ /* lkclXXXX take a guess at a good error message to return :-) */
+ status = 0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
+ }
+
+ /* construct reply. */
+ net_reply_req_chal(&q_r, rdata,
+ &(vuser->dc.srv_chal), status);
+
+}
+
+/*************************************************************************
+ api_net_auth_2:
+ *************************************************************************/
+static void api_net_auth_2( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_AUTH_2 q_a;
+ uint32 status = 0x0;
+
+ DOM_CHAL srv_cred;
+ UTIME srv_time;
+
+ user_struct *vuser;
+
+ if ((vuser = get_valid_user_struct(uid)) == NULL) return;
+
+ srv_time.time = 0;
+
+ /* grab the challenge... */
+ net_io_q_auth_2("", &q_a, data, 0);
+
+ /* check that the client credentials are valid */
+ if (cred_assert(&(q_a.clnt_chal), vuser->dc.sess_key,
+ &(vuser->dc.clnt_cred.challenge), srv_time))
+ {
+
+ /* create server challenge for inclusion in the reply */
+ cred_create(vuser->dc.sess_key, &(vuser->dc.srv_cred.challenge), srv_time, &srv_cred);
+
+ /* copy the received client credentials for use next time */
+ memcpy(vuser->dc.clnt_cred.challenge.data, q_a.clnt_chal.data, sizeof(q_a.clnt_chal.data));
+ memcpy(vuser->dc.srv_cred .challenge.data, q_a.clnt_chal.data, sizeof(q_a.clnt_chal.data));
+ }
+ else
+ {
+ status = NT_STATUS_ACCESS_DENIED | 0xC0000000;
+ }
+
+ /* construct reply. */
+ net_reply_auth_2(&q_a, rdata, &srv_cred, status);
+}
+
+
+/*************************************************************************
+ api_net_srv_pwset:
+ *************************************************************************/
+static void api_net_srv_pwset( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_SRV_PWSET q_a;
+ uint32 status = NT_STATUS_WRONG_PASSWORD|0xC0000000;
+ DOM_CRED srv_cred;
+ pstring mach_acct;
+ struct smb_passwd *smb_pass;
+ BOOL ret;
+ user_struct *vuser;
+
+ if ((vuser = get_valid_user_struct(uid)) == NULL) return;
+
+ /* grab the challenge and encrypted password ... */
+ net_io_q_srv_pwset("", &q_a, data, 0);
+
+ /* checks and updates credentials. creates reply credentials */
+ if (deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
+ &(q_a.clnt_id.cred), &srv_cred))
+ {
+ memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
+
+ DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
+
+ pstrcpy(mach_acct, unistrn2(q_a.clnt_id.login.uni_acct_name.buffer,
+ q_a.clnt_id.login.uni_acct_name.uni_str_len));
+
+ DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
+
+ become_root(True);
+ smb_pass = getsmbpwnam(mach_acct);
+ unbecome_root(True);
+
+ if (smb_pass != NULL)
+ {
+ unsigned char pwd[16];
+ int i;
+
+ DEBUG(100,("Server password set : new given value was :\n"));
+ for(i = 0; i < 16; i++)
+ {
+ DEBUG(100,("%02X ", q_a.pwd[i]));
+ }
+ DEBUG(100,("\n"));
+
+ cred_hash3( pwd, q_a.pwd, vuser->dc.sess_key, 0);
+
+ /* lies! nt and lm passwords are _not_ the same: don't care */
+ smb_pass->smb_passwd = pwd;
+ smb_pass->smb_nt_passwd = pwd;
+ smb_pass->acct_ctrl = ACB_WSTRUST;
+
+ become_root(True);
+ ret = mod_smbpwd_entry(smb_pass,False);
+ unbecome_root(True);
+
+ if (ret)
+ {
+ /* hooray! */
+ status = 0x0;
+ }
+ }
+
+ DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
+
+ }
+ else
+ {
+ /* lkclXXXX take a guess at a sensible error code to return... */
+ status = 0xC0000000 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
+ }
+
+ /* Construct reply. */
+ net_reply_srv_pwset(&q_a, rdata, &srv_cred, status);
+}
+
+
+/*************************************************************************
+ api_net_sam_logoff:
+ *************************************************************************/
+static void api_net_sam_logoff( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_SAM_LOGOFF q_l;
+ NET_ID_INFO_CTR ctr;
+
+ DOM_CRED srv_cred;
+
+ user_struct *vuser;
+
+ if ((vuser = get_valid_user_struct(uid)) == NULL) return;
+
+ /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
+ dynamically allocate it inside net_io_q_sam_logon, at some point */
+ q_l.sam_id.ctr = &ctr;
+
+ /* grab the challenge... */
+ net_io_q_sam_logoff("", &q_l, data, 0);
+
+ /* checks and updates credentials. creates reply credentials */
+ deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
+ &(q_l.sam_id.client.cred), &srv_cred);
+ memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
+
+ /* construct reply. always indicate success */
+ net_reply_sam_logoff(&q_l, rdata,
+ &srv_cred,
+ 0x0);
+}
+
+/*************************************************************************
+ net_login_interactive:
+ *************************************************************************/
+static uint32 net_login_interactive(NET_ID_INFO_1 *id1,
+ struct smb_passwd *smb_pass,
+ user_struct *vuser)
+{
+ uint32 status = 0x0;
+
+ char nt_pwd[16];
+ char lm_pwd[16];
+ unsigned char key[16];
+
+ memset(key, 0, 16);
+ memcpy(key, vuser->dc.sess_key, 8);
+
+ memcpy(lm_pwd, id1->lm_owf.data, 16);
+ memcpy(nt_pwd, id1->nt_owf.data, 16);
+
+ SamOEMhash((uchar *)lm_pwd, key, False);
+ SamOEMhash((uchar *)nt_pwd, key, False);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decrypt of lm owf password:"));
+ dump_data(100, lm_pwd, 16);
+
+ DEBUG(100,("decrypt of nt owf password:"));
+ dump_data(100, nt_pwd, 16);
+#endif
+
+ if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 &&
+ memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
+ {
+ status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
+ }
+
+ return status;
+}
+
+/*************************************************************************
+ net_login_network:
+ *************************************************************************/
+static uint32 net_login_network(NET_ID_INFO_2 *id2,
+ struct smb_passwd *smb_pass,
+ user_struct *vuser)
+{
+ DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
+ id2->hdr_lm_chal_resp.str_str_len,
+ id2->hdr_nt_chal_resp.str_str_len));
+
+ /* JRA. Check the NT password first if it exists - this is a higher quality
+ password, if it exists and it doesn't match - fail. */
+
+ if (id2->hdr_nt_chal_resp.str_str_len == 24 &&
+ smb_pass->smb_nt_passwd != NULL)
+ {
+ if(smb_password_check((char *)id2->nt_chal_resp.buffer,
+ smb_pass->smb_nt_passwd,
+ id2->lm_chal))
+ return 0x0;
+ else
+ return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* lkclXXXX this is not a good place to put disabling of LM hashes in.
+ if that is to be done, first move this entire function into a
+ library routine that calls the two smb_password_check() functions.
+ if disabling LM hashes (which nt can do for security reasons) then
+ an attempt should be made to disable them everywhere (which nt does
+ not do, for various security-hole reasons).
+ */
+
+ if (id2->hdr_lm_chal_resp.str_str_len == 24 &&
+ smb_password_check((char *)id2->lm_chal_resp.buffer,
+ smb_pass->smb_passwd,
+ id2->lm_chal))
+ {
+ return 0x0;
+ }
+
+
+ /* oops! neither password check succeeded */
+
+ return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
+}
+
+/*************************************************************************
+ api_net_sam_logon:
+ *************************************************************************/
+static void api_net_sam_logon( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_SAM_LOGON q_l;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 usr_info;
+ uint32 status = 0x0;
+ DOM_CRED srv_cred;
+ struct smb_passwd *smb_pass = NULL;
+ UNISTR2 *uni_samlogon_user = NULL;
+
+ user_struct *vuser = NULL;
+
+ if ((vuser = get_valid_user_struct(uid)) == NULL)
+ return;
+
+ q_l.sam_id.ctr = &ctr;
+
+ net_io_q_sam_logon("", &q_l, data, 0);
+
+ /* checks and updates credentials. creates reply credentials */
+ if (!deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
+ &(q_l.sam_id.client.cred), &srv_cred))
+ {
+ status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+ else
+ {
+ memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
+ }
+
+ /* find the username */
+
+ if (status == 0)
+ {
+ switch (q_l.sam_id.logon_level)
+ {
+ case INTERACTIVE_LOGON_TYPE:
+ {
+ uni_samlogon_user = &(q_l.sam_id.ctr->auth.id1.uni_user_name);
+
+ DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
+ break;
+ }
+ case NET_LOGON_TYPE:
+ {
+ uni_samlogon_user = &(q_l.sam_id.ctr->auth.id2.uni_user_name);
+
+ DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
+ break;
+ }
+ default:
+ {
+ DEBUG(2,("SAM Logon: unsupported switch value\n"));
+ status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ } /* end switch */
+ } /* end if status == 0 */
+
+ /* check username exists */
+
+ if (status == 0)
+ {
+ pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
+ uni_samlogon_user->uni_str_len));
+
+ DEBUG(3,("User:[%s]\n", samlogon_user));
+
+ /*
+ * Convert to a UNIX username.
+ */
+ map_username(samlogon_user);
+
+ /*
+ * Do any case conversions.
+ */
+ (void)Get_Pwnam(samlogon_user, True);
+
+ become_root(True);
+ smb_pass = getsmbpwnam(samlogon_user);
+ unbecome_root(True);
+
+ if (smb_pass == NULL)
+ status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
+ else if (smb_pass->acct_ctrl & ACB_DISABLED)
+ status = 0xC0000000 | NT_STATUS_ACCOUNT_DISABLED;
+ }
+
+ /* validate password. */
+
+ if (status == 0)
+ {
+ switch (q_l.sam_id.logon_level)
+ {
+ case INTERACTIVE_LOGON_TYPE:
+ {
+ /* interactive login. */
+ status = net_login_interactive(&q_l.sam_id.ctr->auth.id1, smb_pass, vuser);
+ break;
+ }
+ case NET_LOGON_TYPE:
+ {
+ /* network login. lm challenge and 24 byte responses */
+ status = net_login_network(&q_l.sam_id.ctr->auth.id2, smb_pass, vuser);
+ break;
+ }
+ }
+ }
+
+ /* lkclXXXX 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.
+ */
+
+ /* return the profile plus other bits :-) */
+
+ if (status == 0)
+ {
+ DOM_GID *gids = NULL;
+ int num_gids = 0;
+ NTTIME dummy_time;
+ pstring logon_script;
+ pstring profile_path;
+ pstring home_dir;
+ pstring home_drive;
+ pstring my_name;
+ pstring my_workgroup;
+ pstring domain_groups;
+ uint32 r_uid;
+ uint32 r_gid;
+
+ /* set up pointer indicating user/password failed to be found */
+ usr_info.ptr_user_info = 0;
+
+ dummy_time.low = 0xffffffff;
+ dummy_time.high = 0x7fffffff;
+
+ /* XXXX hack to get standard_sub_basic() to use sam logon username */
+ /* possibly a better way would be to do a become_user() call */
+ sam_logon_in_ssb = True;
+
+ pstrcpy(logon_script, lp_logon_script());
+ pstrcpy(profile_path, lp_logon_path());
+
+ pstrcpy(my_workgroup, lp_workgroup());
+
+ pstrcpy(home_drive, lp_logon_drive());
+ pstrcpy(home_dir, lp_logon_home());
+
+ 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.
+ */
+
+ get_domain_user_groups(domain_groups, samlogon_user);
+
+ /*
+ * make_dom_gids allocates the gids array. JRA.
+ */
+ gids = NULL;
+ num_gids = make_dom_gids(domain_groups, &gids);
+
+ sam_logon_in_ssb = False;
+
+ if (pdb_name_to_rid(samlogon_user, &r_uid, &r_gid))
+ {
+ make_net_user_info3(&usr_info,
+ &dummy_time, /* logon_time */
+ &dummy_time, /* logoff_time */
+ &dummy_time, /* kickoff_time */
+ &dummy_time, /* pass_last_set_time */
+ &dummy_time, /* pass_can_change_time */
+ &dummy_time, /* pass_must_change_time */
+
+ samlogon_user , /* user_name */
+ vuser->real_name, /* full_name */
+ logon_script , /* logon_script */
+ profile_path , /* profile_path */
+ home_dir , /* home_dir */
+ home_drive , /* dir_drive */
+
+ 0, /* logon_count */
+ 0, /* bad_pw_count */
+
+ r_uid , /* RID user_id */
+ r_gid , /* RID group_id */
+ num_gids, /* uint32 num_groups */
+ gids , /* DOM_GID *gids */
+ 0x20 , /* uint32 user_flgs (?) */
+
+ NULL, /* char sess_key[16] */
+
+ my_name , /* char *logon_srv */
+ my_workgroup, /* char *logon_dom */
+
+ &global_machine_sid, /* DOM_SID *dom_sid */
+ NULL); /* char *other_sids */
+ }
+ else
+ {
+ status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* Free any allocated groups array. */
+ if(gids)
+ free((char *)gids);
+ }
+
+ net_reply_sam_logon(&q_l, rdata, &srv_cred, &usr_info, status);
+}
+
+
+/*************************************************************************
+ api_net_trust_dom_list:
+ *************************************************************************/
+static void api_net_trust_dom_list( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_TRUST_DOM_LIST q_t;
+
+ char *trusted_domain = "test_domain";
+
+ DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
+
+ /* grab the lsa trusted domain list query... */
+ net_io_q_trust_dom("", &q_t, data, 0);
+
+ /* construct reply. */
+ net_reply_trust_dom_list(&q_t, rdata,
+ 1, trusted_domain);
+
+ DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
+}
+
+
+/*************************************************************************
+ error messages cropping up when using nltest.exe...
+ *************************************************************************/
+#define ERROR_NO_SUCH_DOMAIN 0x54b
+#define ERROR_NO_LOGON_SERVERS 0x51f
+
+/*************************************************************************
+ api_net_logon_ctrl2:
+ *************************************************************************/
+static void api_net_logon_ctrl2( int uid,
+ prs_struct *data,
+ prs_struct *rdata)
+{
+ NET_Q_LOGON_CTRL2 q_l;
+
+ /* lkclXXXX - guess what - absolutely no idea what these are! */
+ 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(6,("api_net_logon_ctrl2: %d\n", __LINE__));
+
+ /* grab the lsa netlogon ctrl2 query... */
+ net_io_q_logon_ctrl2("", &q_l, data, 0);
+
+ /* construct reply. */
+ net_reply_logon_ctrl2(&q_l, rdata,
+ flags, pdc_connection_status, logon_attempts,
+ tc_status, trusted_domain);
+
+ DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ array of \PIPE\NETLOGON operations
+ ********************************************************************/
+static struct api_struct api_net_cmds [] =
+{
+ { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal },
+ { "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 },
+ { NULL , 0 , NULL }
+};
+
+/*******************************************************************
+ receives a netlogon pipe and responds.
+ ********************************************************************/
+BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds, data);
+}
diff --git a/source/rpc_server/srv_pipe_hnd.c b/source/rpc_server/srv_pipe_hnd.c
new file mode 100644
index 00000000000..cf7fc9334ec
--- /dev/null
+++ b/source/rpc_server/srv_pipe_hnd.c
@@ -0,0 +1,340 @@
+
+/*
+ * 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,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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)
+
+/* this must be larger than the sum of the open files and directories */
+#define PIPE_HANDLE_OFFSET 0x7000
+
+extern int DEBUGLEVEL;
+static pipes_struct *chain_p;
+static int pipes_open;
+
+#ifndef MAX_OPEN_PIPES
+#define MAX_OPEN_PIPES 64
+#endif
+
+static pipes_struct *Pipes;
+static struct bitmap *bmap;
+
+/****************************************************************************
+ 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\n");
+ }
+}
+
+
+/****************************************************************************
+ find first available file 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 = (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 pipes: name %s pnum=%x\n", p->name, p->pnum));
+ }
+
+ p = (pipes_struct *)malloc(sizeof(*p));
+ if (!p) return NULL;
+
+ ZERO_STRUCTP(p);
+ DLIST_ADD(Pipes, p);
+
+ bitmap_set(bmap, i);
+ i += PIPE_HANDLE_OFFSET;
+
+ pipes_open++;
+
+ p->pnum = i;
+
+ p->open = True;
+ p->device_state = 0;
+ p->conn = conn;
+ p->uid = vuid;
+
+ p->rhdr.data = NULL;
+ p->rdata.data = NULL;
+ p->rhdr.offset = 0;
+ p->rdata.offset = 0;
+
+ p->file_offset = 0;
+ p->hdr_offsets = 0;
+ p->frag_len_left = 0;
+ p->next_frag_start = 0;
+
+ 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;
+}
+
+
+/****************************************************************************
+ reads data from a pipe.
+
+ headers are interspersed with the data at regular 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_request() here is a fudge. the data should already
+ have been prepared into arrays of headers + data stream sections.
+
+ ****************************************************************************/
+int read_pipe(pipes_struct *p, char *data, uint32 pos, int n)
+{
+ int num = 0;
+ int len = 0;
+ uint32 hdr_num = 0;
+ int data_hdr_pos;
+ int data_pos;
+
+ DEBUG(6,("read_pipe: %x", p->pnum));
+
+ DEBUG(6,("name: %s open: %s pos: %d len: %d",
+ p->name,
+ BOOLSTR(p->open),
+ pos, n));
+
+ if (!p || !p->open) {
+ DEBUG(6,("pipe not open\n"));
+ return -1;
+ }
+
+
+ if (p->rhdr.data == NULL || p->rhdr.data->data == NULL ||
+ p->rhdr.data->data_used == 0) {
+ return 0;
+ }
+
+ DEBUG(6,("read_pipe: p: %p file_offset: %d file_pos: %d\n",
+ p, p->file_offset, n));
+ DEBUG(6,("read_pipe: frag_len_left: %d next_frag_start: %d\n",
+ p->frag_len_left, p->next_frag_start));
+
+ /* the read request starts from where the SMBtrans2 left off. */
+ data_pos = p->file_offset - p->hdr_offsets;
+ data_hdr_pos = p->file_offset;
+
+ len = mem_buf_len(p->rhdr.data);
+ num = len - (int)data_pos;
+
+ DEBUG(6,("read_pipe: len: %d num: %d n: %d\n", len, num, n));
+
+ if (num > n) num = n;
+ if (num <= 0) {
+ DEBUG(5,("read_pipe: 0 or -ve data length\n"));
+ return 0;
+ }
+
+ if (!IS_BITS_SET_ALL(p->hdr.flags, RPC_FLG_LAST)) {
+ /* intermediate fragment - possibility of another header */
+
+ DEBUG(5,("read_pipe: frag_len: %d data_pos: %d data_hdr_pos: %d\n",
+ p->hdr.frag_len, data_pos, data_hdr_pos));
+
+ if (data_hdr_pos == p->next_frag_start) {
+ DEBUG(6,("read_pipe: next fragment header\n"));
+
+ /* this is subtracted from the total data bytes, later */
+ hdr_num = 0x18;
+
+ /* create and copy in a new header. */
+ create_rpc_reply(p, data_pos, p->rdata.offset);
+ mem_buf_copy(data, p->rhdr.data, 0, 0x18);
+
+ data += 0x18;
+ p->frag_len_left = p->hdr.frag_len;
+ p->next_frag_start += p->hdr.frag_len;
+ p->hdr_offsets += 0x18;
+ }
+
+ }
+
+ if (num < hdr_num) {
+ DEBUG(5,("read_pipe: warning - data read only part of a header\n"));
+ }
+
+ DEBUG(6,("read_pipe: adjusted data_pos: %d num-hdr_num: %d\n",
+ data_pos, num - hdr_num));
+ mem_buf_copy(data, p->rhdr.data, data_pos, num - hdr_num);
+
+ data_pos += num;
+ data_hdr_pos += num;
+
+ if (hdr_num == 0x18 && num == 0x18) {
+ DEBUG(6,("read_pipe: just header read\n"));
+
+ /* advance to the next fragment */
+ p->frag_len_left -= 0x18;
+ } else if (data_hdr_pos == p->next_frag_start) {
+ DEBUG(6,("read_pipe: next fragment expected\n"));
+ }
+
+ p->file_offset += num;
+
+ return num;
+}
+
+
+/****************************************************************************
+ 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,("%s Setting pipe device state=%x on pipe (name=%s)\n",
+ timestring(), device_state, p->name));
+
+ p->device_state = device_state;
+
+ return True;
+ }
+
+ DEBUG(3,("%s Error setting pipe device state=%x (name=%s)\n",
+ timestring(), 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;
+ }
+
+ mem_buf_free(&(p->rdata.data));
+ mem_buf_free(&(p->rhdr .data));
+
+ 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);
+
+ ZERO_STRUCTP(p);
+
+ free(p);
+
+ return True;
+}
+
+/****************************************************************************
+ close an rpc pipe
+****************************************************************************/
+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);
+}
+
+/****************************************************************************
+ close an rpc pipe
+****************************************************************************/
+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..3f9cdc20f49
--- /dev/null
+++ b/source/rpc_server/srv_reg.c
@@ -0,0 +1,240 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+
+/*******************************************************************
+ reg_reply_unknown_1
+ ********************************************************************/
+static void reg_reply_close(REG_Q_CLOSE *q_r,
+ prs_struct *rdata)
+{
+ REG_R_CLOSE r_u;
+
+ /* set up the REG unknown_1 response */
+ bzero(r_u.pol.data, POL_HND_SIZE);
+
+ /* close the policy handle */
+ if (close_lsa_policy_hnd(&(q_r->pol)))
+ {
+ r_u.status = 0;
+ }
+ else
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ DEBUG(5,("reg_unknown_1: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ reg_io_r_close("", &r_u, rdata, 0);
+
+ DEBUG(5,("reg_unknown_1: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ api_reg_close
+ ********************************************************************/
+static void api_reg_close( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ REG_Q_CLOSE q_r;
+
+ /* grab the reg unknown 1 */
+ reg_io_q_close("", &q_r, data, 0);
+
+ /* construct reply. always indicate success */
+ reg_reply_close(&q_r, rdata);
+}
+
+
+/*******************************************************************
+ reg_reply_open
+ ********************************************************************/
+static void reg_reply_open(REG_Q_OPEN_POLICY *q_r,
+ prs_struct *rdata)
+{
+ REG_R_OPEN_POLICY r_u;
+
+ r_u.status = 0x0;
+ /* get a (unique) handle. open a policy on it. */
+ if (r_u.status == 0x0 && !open_lsa_policy_hnd(&(r_u.pol)))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ DEBUG(5,("reg_open: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ reg_io_r_open_policy("", &r_u, rdata, 0);
+
+ DEBUG(5,("reg_open: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ api_reg_open
+ ********************************************************************/
+static void api_reg_open( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ REG_Q_OPEN_POLICY q_u;
+
+ /* grab the reg open */
+ reg_io_q_open_policy("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ reg_reply_open(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ reg_reply_open_entry
+ ********************************************************************/
+static void reg_reply_open_entry(REG_Q_OPEN_ENTRY *q_u,
+ prs_struct *rdata)
+{
+ uint32 status = 0;
+ POLICY_HND pol;
+ REG_R_OPEN_ENTRY r_u;
+ fstring name;
+
+ DEBUG(5,("reg_open_entry: %d\n", __LINE__));
+
+ if (status == 0 && find_lsa_policy_by_hnd(&(q_u->pol)) == -1)
+ {
+ status = 0xC000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (status == 0x0 && !open_lsa_policy_hnd(&pol))
+ {
+ status = 0xC000000 | NT_STATUS_TOO_MANY_SECRETS; /* ha ha very droll */
+ }
+
+ fstrcpy(name, unistrn2(q_u->uni_name.buffer, q_u->uni_name.uni_str_len));
+
+ if (status == 0x0)
+ {
+ DEBUG(5,("reg_open_entry: %s\n", name));
+ /* lkcl XXXX do a check on the name, here */
+ }
+
+ if (status == 0x0 && !set_lsa_policy_reg_name(&pol, name))
+ {
+ status = 0xC000000 | NT_STATUS_TOO_MANY_SECRETS; /* ha ha very droll */
+ }
+
+ make_reg_r_open_entry(&r_u, &pol, status);
+
+ /* store the response in the SMB stream */
+ reg_io_r_open_entry("", &r_u, rdata, 0);
+
+ DEBUG(5,("reg_open_entry: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ api_reg_open_entry
+ ********************************************************************/
+static void api_reg_open_entry( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ REG_Q_OPEN_ENTRY q_u;
+
+ /* grab the reg open entry */
+ reg_io_q_open_entry("", &q_u, data, 0);
+
+ /* construct reply. */
+ reg_reply_open_entry(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ reg_reply_info
+ ********************************************************************/
+static void reg_reply_info(REG_Q_INFO *q_u,
+ prs_struct *rdata)
+{
+ uint32 status = 0;
+
+ REG_R_INFO r_u;
+
+ DEBUG(5,("reg_info: %d\n", __LINE__));
+
+ if (status == 0 && find_lsa_policy_by_hnd(&(q_u->pol)) == -1)
+ {
+ status = 0xC000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (status == 0)
+ {
+ }
+
+ make_reg_r_info(&r_u, 1, "LanmanNT", 0x12, 0x12, status);
+
+ /* store the response in the SMB stream */
+ reg_io_r_info("", &r_u, rdata, 0);
+
+ DEBUG(5,("reg_open_entry: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ api_reg_info
+ ********************************************************************/
+static void api_reg_info( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ REG_Q_INFO q_u;
+
+ /* grab the reg unknown 0x11*/
+ reg_io_q_info("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ reg_reply_info(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ 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_POLICY , api_reg_open },
+ { "REG_INFO" , REG_INFO , api_reg_info },
+ { NULL, 0 , NULL }
+};
+
+/*******************************************************************
+ receives a reg pipe and responds.
+ ********************************************************************/
+BOOL api_reg_rpc(pipes_struct *p, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_reg_rpc", api_reg_cmds, data);
+}
+
diff --git a/source/rpc_server/srv_samr.c b/source/rpc_server/srv_samr.c
new file mode 100644
index 00000000000..c2140db36f8
--- /dev/null
+++ b/source/rpc_server/srv_samr.c
@@ -0,0 +1,1311 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+extern BOOL sam_logon_in_ssb;
+extern pstring samlogon_user;
+extern DOM_SID global_machine_sid;
+
+extern rid_name domain_group_rids[];
+extern rid_name domain_alias_rids[];
+
+/*******************************************************************
+ This next function should be replaced with something that
+ dynamically returns the correct user info..... JRA.
+ ********************************************************************/
+
+static BOOL get_sampwd_entries(SAM_USER_INFO_21 *pw_buf,
+ int *total_entries, int *num_entries,
+ int max_num_entries,
+ uint16 acb_mask)
+{
+ void *vp = NULL;
+ struct sam_passwd *pwd = NULL;
+
+ (*num_entries) = 0;
+ (*total_entries) = 0;
+
+ if (pw_buf == NULL) return False;
+
+ vp = startsmbpwent(False);
+ if (!vp)
+ {
+ DEBUG(0, ("get_sampwd_entries: Unable to open SMB password database.\n"));
+ return False;
+ }
+
+ while (((pwd = getsam21pwent(vp)) != NULL) && (*num_entries) < max_num_entries)
+ {
+ int user_name_len = strlen(pwd->smb_name);
+ make_unistr2(&(pw_buf[(*num_entries)].uni_user_name), pwd->smb_name, user_name_len-1);
+ make_uni_hdr(&(pw_buf[(*num_entries)].hdr_user_name), user_name_len-1,
+ user_name_len-1, 1);
+ pw_buf[(*num_entries)].user_rid = pwd->user_rid;
+ bzero( pw_buf[(*num_entries)].nt_pwd , 16);
+
+ /* Now check if the NT compatible password is available. */
+ if (pwd->smb_nt_passwd != NULL)
+ {
+ memcpy( pw_buf[(*num_entries)].nt_pwd , pwd->smb_nt_passwd, 16);
+ }
+
+ pw_buf[(*num_entries)].acb_info = (uint16)pwd->acct_ctrl;
+
+ DEBUG(5, ("entry idx: %d user %s, rid 0x%x, acb %x",
+ (*num_entries), pwd->smb_name, pwd->user_rid, pwd->acct_ctrl));
+
+ if (acb_mask == 0 || IS_BITS_SET_SOME(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)++;
+ }
+
+ endsmbpwent(vp);
+
+ return (*num_entries) > 0;
+}
+
+/*******************************************************************
+ samr_reply_unknown_1
+ ********************************************************************/
+static void samr_reply_close_hnd(SAMR_Q_CLOSE_HND *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_CLOSE_HND r_u;
+
+ /* set up the SAMR unknown_1 response */
+ bzero(r_u.pol.data, POL_HND_SIZE);
+
+ /* close the policy handle */
+ if (close_lsa_policy_hnd(&(q_u->pol)))
+ {
+ r_u.status = 0;
+ }
+ else
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_INVALID;
+ }
+
+ DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_close_hnd("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_close_hnd
+ ********************************************************************/
+static void api_samr_close_hnd( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_CLOSE_HND q_u;
+
+ /* grab the samr unknown 1 */
+ samr_io_q_close_hnd("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_close_hnd(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_open_domain
+ ********************************************************************/
+static void samr_reply_open_domain(SAMR_Q_OPEN_DOMAIN *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_OPEN_DOMAIN r_u;
+ BOOL pol_open = False;
+
+ r_u.status = 0x0;
+
+ /* find the connection policy handle. */
+ if (r_u.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->connect_pol)) == -1))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* get a (unique) handle. open a policy on it. */
+ if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.domain_pol))))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* associate the domain SID with the (unique) handle. */
+ if (r_u.status == 0x0 && !set_lsa_policy_samr_sid(&(r_u.domain_pol), &(q_u->dom_sid.sid)))
+ {
+ /* oh, whoops. don't know what error message to return, here */
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (r_u.status != 0 && pol_open)
+ {
+ close_lsa_policy_hnd(&(r_u.domain_pol));
+ }
+
+ DEBUG(5,("samr_open_domain: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_open_domain("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_open_domain: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_open_domain
+ ********************************************************************/
+static void api_samr_open_domain( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_OPEN_DOMAIN q_u;
+
+ /* grab the samr open */
+ samr_io_q_open_domain("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_open_domain(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_unknown_3
+ ********************************************************************/
+static void samr_reply_unknown_3(SAMR_Q_UNKNOWN_3 *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_UNKNOWN_3 r_u;
+ DOM_SID3 sid[MAX_SAM_SIDS];
+ uint32 rid;
+ uint32 status;
+
+ status = 0x0;
+
+ /* find the policy handle. open a policy on it. */
+ if (status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->user_pol)) == -1))
+ {
+ status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* find the user's rid */
+ if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->user_pol))) == 0xffffffff)
+ {
+ status = NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (status == 0x0)
+ {
+ DOM_SID user_sid;
+ DOM_SID other_sid;
+
+ user_sid = global_machine_sid;
+
+ SMB_ASSERT_ARRAY(user_sid.sub_auths, user_sid.num_auths+1);
+
+ /*
+ * Add the user RID.
+ */
+ user_sid.sub_auths[user_sid.num_auths++] = rid;
+
+ string_to_sid(&other_sid, "S-1-1");
+
+ /* maybe need another 1 or 2 (S-1-5-20-0x220 and S-1-5-20-0x224) */
+ /* these two are DOMAIN_ADMIN and DOMAIN_ACCT_OP group RIDs */
+ make_dom_sid3(&(sid[0]), 0x035b, 0x0002, &other_sid);
+ make_dom_sid3(&(sid[1]), 0x0044, 0x0002, &user_sid);
+ }
+
+ make_samr_r_unknown_3(&r_u,
+ 0x0001, 0x8004,
+ 0x00000014, 0x0002, 0x0070,
+ 2, sid, status);
+
+ DEBUG(5,("samr_unknown_3: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_unknown_3("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_unknown_3: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_unknown_3
+ ********************************************************************/
+static void api_samr_unknown_3( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_UNKNOWN_3 q_u;
+
+ /* grab the samr open */
+ samr_io_q_unknown_3("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_unknown_3(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_enum_dom_users
+ ********************************************************************/
+static void samr_reply_enum_dom_users(SAMR_Q_ENUM_DOM_USERS *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_ENUM_DOM_USERS r_e;
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries;
+ int total_entries;
+
+ r_e.status = 0x0;
+ r_e.total_num_entries = 0;
+
+ /* find the policy handle. open a policy on it. */
+ if (r_e.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(5,("samr_reply_enum_dom_users: %d\n", __LINE__));
+
+ become_root(True);
+ get_sampwd_entries(pass, &total_entries, &num_entries, MAX_SAM_ENTRIES, q_u->acb_mask);
+ unbecome_root(True);
+
+ make_samr_r_enum_dom_users(&r_e, total_entries,
+ q_u->unknown_0, num_entries,
+ pass, r_e.status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_enum_dom_users("", &r_e, rdata, 0);
+
+ DEBUG(5,("samr_enum_dom_users: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_enum_dom_users
+ ********************************************************************/
+static void api_samr_enum_dom_users( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_ENUM_DOM_USERS q_e;
+
+ /* grab the samr open */
+ samr_io_q_enum_dom_users("", &q_e, data, 0);
+
+ /* construct reply. */
+ samr_reply_enum_dom_users(&q_e, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_enum_dom_groups
+ ********************************************************************/
+static void samr_reply_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_ENUM_DOM_GROUPS r_e;
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries;
+ BOOL got_grps;
+ char *dummy_group = "Domain Admins";
+
+ r_e.status = 0x0;
+ r_e.num_entries = 0;
+
+ /* find the policy handle. open a policy on it. */
+ if (r_e.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__));
+
+ got_grps = True;
+ num_entries = 1;
+ make_unistr2(&(pass[0].uni_user_name), dummy_group, strlen(dummy_group));
+ pass[0].user_rid = DOMAIN_GROUP_RID_ADMINS;
+
+ if (r_e.status == 0 && got_grps)
+ {
+ make_samr_r_enum_dom_groups(&r_e, q_u->start_idx, num_entries, pass, r_e.status);
+ }
+
+ /* store the response in the SMB stream */
+ samr_io_r_enum_dom_groups("", &r_e, rdata, 0);
+
+ DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_enum_dom_groups
+ ********************************************************************/
+static void api_samr_enum_dom_groups( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_ENUM_DOM_GROUPS q_e;
+
+ /* grab the samr open */
+ samr_io_q_enum_dom_groups("", &q_e, data, 0);
+
+ /* construct reply. */
+ samr_reply_enum_dom_groups(&q_e, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_enum_dom_aliases
+ ********************************************************************/
+static void samr_reply_enum_dom_aliases(SAMR_Q_ENUM_DOM_ALIASES *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_ENUM_DOM_ALIASES r_e;
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries;
+ BOOL got_aliases;
+ char *dummy_alias = "admins";
+
+ r_e.status = 0x0;
+ r_e.num_entries = 0;
+
+ /* find the policy handle. open a policy on it. */
+ if (r_e.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(5,("samr_reply_enum_dom_aliases: %d\n", __LINE__));
+
+ got_aliases = True;
+ num_entries = 1;
+ make_unistr2(&(pass[0].uni_user_name), dummy_alias, strlen(dummy_alias));
+ pass[0].user_rid = BUILTIN_ALIAS_RID_ADMINS;
+
+ if (r_e.status == 0 && got_aliases)
+ {
+ make_samr_r_enum_dom_aliases(&r_e, num_entries, pass, r_e.status);
+ }
+
+ /* store the response in the SMB stream */
+ samr_io_r_enum_dom_aliases("", &r_e, rdata, 0);
+
+ DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_enum_dom_aliases
+ ********************************************************************/
+static void api_samr_enum_dom_aliases( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_ENUM_DOM_ALIASES q_e;
+
+ /* grab the samr open */
+ samr_io_q_enum_dom_aliases("", &q_e, data, 0);
+
+ /* construct reply. */
+ samr_reply_enum_dom_aliases(&q_e, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_query_dispinfo
+ ********************************************************************/
+static void samr_reply_query_dispinfo(SAMR_Q_QUERY_DISPINFO *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_QUERY_DISPINFO r_e;
+ SAM_INFO_CTR ctr;
+ SAM_INFO_1 info1;
+ SAM_INFO_2 info2;
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries;
+ int total_entries;
+ BOOL got_pwds;
+ uint16 switch_level = 0x0;
+
+ r_e.status = 0x0;
+
+ /* find the policy handle. open a policy on it. */
+ if (r_e.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(5,("samr_reply_query_dispinfo: %d\n", __LINE__));
+
+ become_root(True);
+ got_pwds = get_sampwd_entries(pass, &total_entries, &num_entries, MAX_SAM_ENTRIES, 0);
+ unbecome_root(True);
+
+ switch (q_u->switch_level)
+ {
+ case 0x1:
+ {
+
+ /* query disp info is for users */
+ switch_level = 0x1;
+ make_sam_info_1(&info1, ACB_NORMAL,
+ q_u->start_idx, num_entries, pass);
+
+ ctr.sam.info1 = &info1;
+
+ break;
+ }
+ case 0x2:
+ {
+ /* query disp info is for servers */
+ switch_level = 0x2;
+ make_sam_info_2(&info2, ACB_WSTRUST,
+ q_u->start_idx, num_entries, pass);
+
+ ctr.sam.info2 = &info2;
+
+ break;
+ }
+ }
+
+ if (r_e.status == 0 && got_pwds)
+ {
+ make_samr_r_query_dispinfo(&r_e, switch_level, &ctr, r_e.status);
+ }
+
+ /* store the response in the SMB stream */
+ samr_io_r_query_dispinfo("", &r_e, rdata, 0);
+
+ DEBUG(5,("samr_query_dispinfo: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_query_dispinfo
+ ********************************************************************/
+static void api_samr_query_dispinfo( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_QUERY_DISPINFO q_e;
+
+ /* grab the samr open */
+ samr_io_q_query_dispinfo("", &q_e, data, 0);
+
+ /* construct reply. */
+ samr_reply_query_dispinfo(&q_e, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_query_aliasinfo
+ ********************************************************************/
+static void samr_reply_query_aliasinfo(SAMR_Q_QUERY_ALIASINFO *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_QUERY_ALIASINFO r_e;
+
+ r_e.status = 0x0;
+ r_e.ptr = 0;
+
+ /* find the policy handle. open a policy on it. */
+ if (r_e.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ DEBUG(5,("samr_reply_query_aliasinfo: %d\n", __LINE__));
+
+ if (r_e.status == 0x0)
+ {
+ if (q_u->switch_level != 3)
+ {
+ r_e.status = NT_STATUS_INVALID_INFO_CLASS;
+ }
+ }
+
+ make_samr_r_query_aliasinfo(&r_e, q_u->switch_level,
+ "<account description>",
+ r_e.status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_query_aliasinfo("", &r_e, rdata, 0);
+
+ DEBUG(5,("samr_query_aliasinfo: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_query_aliasinfo
+ ********************************************************************/
+static void api_samr_query_aliasinfo( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_QUERY_ALIASINFO q_e;
+
+ /* grab the samr open */
+ samr_io_q_query_aliasinfo("", &q_e, data, 0);
+
+ /* construct reply. */
+ samr_reply_query_aliasinfo(&q_e, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_lookup_ids
+ ********************************************************************/
+static void samr_reply_lookup_ids(SAMR_Q_LOOKUP_IDS *q_u,
+ prs_struct *rdata)
+{
+ uint32 rid[MAX_SAM_ENTRIES];
+ uint32 status = 0;
+ int num_rids = q_u->num_sids1;
+
+ SAMR_R_LOOKUP_IDS r_u;
+
+ 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(True);
+ sam_pass = get_smb21pwd_entry(user_name, 0);
+ unbecome_root(True);
+
+ 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;
+
+ make_samr_r_lookup_ids(&r_u, num_rids, rid, status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_lookup_ids("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_lookup_ids: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_lookup_ids
+ ********************************************************************/
+static void api_samr_lookup_ids( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_LOOKUP_IDS q_u;
+
+ /* grab the samr 0x10 */
+ samr_io_q_lookup_ids("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_lookup_ids(&q_u, rdata);
+}
+
+/*******************************************************************
+ samr_reply_lookup_names
+ ********************************************************************/
+static void samr_reply_lookup_names(SAMR_Q_LOOKUP_NAMES *q_u,
+ prs_struct *rdata)
+{
+ uint32 rid[MAX_SAM_ENTRIES];
+ uint32 status = 0;
+ int i;
+ int num_rids = q_u->num_rids1;
+
+ SAMR_R_LOOKUP_NAMES r_u;
+
+ DEBUG(5,("samr_lookup_names: %d\n", __LINE__));
+
+ if (num_rids > MAX_SAM_ENTRIES)
+ {
+ num_rids = MAX_SAM_ENTRIES;
+ DEBUG(5,("samr_lookup_names: truncating entries to %d\n", num_rids));
+ }
+
+ SMB_ASSERT_ARRAY(q_u->uni_user_name, num_rids);
+
+ for (i = 0; i < num_rids && status == 0; i++)
+ {
+ fstring name;
+
+ status = 0xC0000000 | NT_STATUS_NONE_MAPPED;
+
+ fstrcpy(name, unistrn2(q_u->uni_user_name[i].buffer, q_u->uni_user_name[i].uni_str_len));
+
+ status = (status != 0x0) ? lookup_user_rid (name, &(rid[i])) : status;
+ status = (status != 0x0) ? lookup_group_rid(name, &(rid[i])) : status;
+ status = (status != 0x0) ? lookup_alias_rid(name, &(rid[i])) : status;
+ }
+
+ make_samr_r_lookup_names(&r_u, num_rids, rid, status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_lookup_names("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_lookup_names: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_lookup_names
+ ********************************************************************/
+static void api_samr_lookup_names( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_LOOKUP_NAMES q_u;
+
+ /* grab the samr lookup names */
+ samr_io_q_lookup_names("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_lookup_names(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_unknown_12
+ ********************************************************************/
+static void samr_reply_unknown_12(SAMR_Q_UNKNOWN_12 *q_u,
+ prs_struct *rdata)
+{
+ fstring group_names[MAX_SAM_ENTRIES];
+ uint32 group_attrs[MAX_SAM_ENTRIES];
+ uint32 status = 0;
+ int num_gids = q_u->num_gids1;
+
+ SAMR_R_UNKNOWN_12 r_u;
+
+ DEBUG(5,("samr_unknown_12: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ if (status == 0x0)
+ {
+ int i;
+ if (num_gids > MAX_SAM_ENTRIES)
+ {
+ num_gids = MAX_SAM_ENTRIES;
+ DEBUG(5,("samr_unknown_12: truncating entries to %d\n", num_gids));
+ }
+
+ for (i = 0; i < num_gids && status == 0; i++)
+ {
+ fstrcpy(group_names[i], "dummy group");
+ group_attrs[i] = 0x2;
+ }
+ }
+
+ make_samr_r_unknown_12(&r_u, num_gids, group_names, group_attrs, status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_unknown_12("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_unknown_12: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_unknown_12
+ ********************************************************************/
+static void api_samr_unknown_12( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_UNKNOWN_12 q_u;
+
+ /* grab the samr lookup names */
+ samr_io_q_unknown_12("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_unknown_12(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_open_user
+ ********************************************************************/
+static void samr_reply_open_user(SAMR_Q_OPEN_USER *q_u,
+ prs_struct *rdata,
+ int status)
+{
+ SAMR_R_OPEN_USER r_u;
+ struct sam_passwd *sam_pass;
+ BOOL pol_open = False;
+
+ /* set up the SAMR open_user response */
+ bzero(r_u.user_pol.data, POL_HND_SIZE);
+
+ r_u.status = 0x0;
+
+ /* find the policy handle. open a policy on it. */
+ if (r_u.status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->domain_pol)) == -1))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* get a (unique) handle. open a policy on it. */
+ if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.user_pol))))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ become_root(True);
+ sam_pass = getsam21pwrid(q_u->user_rid);
+ unbecome_root(True);
+
+ /* check that the RID exists in our domain. */
+ if (r_u.status == 0x0 && sam_pass == NULL)
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
+ }
+
+ /* associate the RID with the (unique) handle. */
+ if (r_u.status == 0x0 && !set_lsa_policy_samr_rid(&(r_u.user_pol), q_u->user_rid))
+ {
+ /* oh, whoops. don't know what error message to return, here */
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (r_u.status != 0 && pol_open)
+ {
+ close_lsa_policy_hnd(&(r_u.user_pol));
+ }
+
+ DEBUG(5,("samr_open_user: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_open_user("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_open_user: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_open_user
+ ********************************************************************/
+static void api_samr_open_user( int rid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_OPEN_USER q_u;
+
+ /* grab the samr unknown 22 */
+ samr_io_q_open_user("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_open_user(&q_u, rdata, 0x0);
+}
+
+
+/*************************************************************************
+ get_user_info_21
+ *************************************************************************/
+static BOOL get_user_info_21(SAM_USER_INFO_21 *id21, uint32 user_rid)
+{
+ NTTIME dummy_time;
+ struct sam_passwd *sam_pass;
+ LOGON_HRS hrs;
+ int i;
+
+#ifdef DONT_CHECK_THIS_FOR_NOW
+ if (!pdb_rid_is_user(user_rid))
+ {
+ DEBUG(4,("RID 0x%x is not a user RID\n", user_rid));
+ return False;
+ }
+#endif
+
+ become_root(True);
+ sam_pass = getsam21pwrid(user_rid);
+ unbecome_root(True);
+
+ if (sam_pass == NULL)
+ {
+ DEBUG(4,("User 0x%x not found\n", user_rid));
+ return False;
+ }
+
+ DEBUG(3,("User:[%s]\n", sam_pass->smb_name));
+
+ dummy_time.low = 0xffffffff;
+ dummy_time.high = 0x7fffffff;
+
+ DEBUG(0,("get_user_info_21 - TODO: convert unix times to NTTIMEs\n"));
+
+ /* create a LOGON_HRS structure */
+ hrs.len = sam_pass->hours_len;
+ SMB_ASSERT_ARRAY(hrs.hours, hrs.len);
+ for (i = 0; i < hrs.len; i++)
+ {
+ hrs.hours[i] = sam_pass->hours[i];
+ }
+
+ make_sam_user_info21(id21,
+
+ &dummy_time, /* logon_time */
+ &dummy_time, /* logoff_time */
+ &dummy_time, /* kickoff_time */
+ &dummy_time, /* pass_last_set_time */
+ &dummy_time, /* pass_can_change_time */
+ &dummy_time, /* pass_must_change_time */
+
+ sam_pass->smb_name, /* user_name */
+ sam_pass->full_name, /* full_name */
+ sam_pass->home_dir, /* home_dir */
+ sam_pass->dir_drive, /* dir_drive */
+ sam_pass->logon_script, /* logon_script */
+ sam_pass->profile_path, /* profile_path */
+ sam_pass->acct_desc, /* description */
+ sam_pass->workstations, /* workstations user can log in from */
+ sam_pass->unknown_str, /* don't know, yet */
+ sam_pass->munged_dial, /* dialin info. contains dialin path and tel no */
+
+ sam_pass->user_rid, /* RID user_id */
+ sam_pass->group_rid, /* RID group_id */
+ sam_pass->acct_ctrl,
+
+ sam_pass->unknown_3, /* unknown_3 */
+ sam_pass->logon_divs, /* divisions per week */
+ &hrs, /* logon hours */
+ sam_pass->unknown_5,
+ sam_pass->unknown_6);
+
+ return True;
+}
+
+/*******************************************************************
+ samr_reply_query_userinfo
+ ********************************************************************/
+static void samr_reply_query_userinfo(SAMR_Q_QUERY_USERINFO *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_QUERY_USERINFO r_u;
+#if 0
+ SAM_USER_INFO_11 id11;
+#endif
+ SAM_USER_INFO_21 id21;
+ void *info = NULL;
+
+ uint32 status = 0x0;
+ uint32 rid = 0x0;
+
+ DEBUG(5,("samr_reply_query_userinfo: %d\n", __LINE__));
+
+ /* search for the handle */
+ if (status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ status = NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* find the user's rid */
+ if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->pol))) == 0xffffffff)
+ {
+ status = NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ DEBUG(5,("samr_reply_query_userinfo: rid:0x%x\n", rid));
+
+ /* ok! user info levels (there are lots: see MSDEV help), off we go... */
+ if (status == 0x0)
+ {
+ switch (q_u->switch_value)
+ {
+#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;
+
+ make_sam_user_info11(&id11, &expire, "BROOKFIELDS$", 0x03ef, 0x201, 0x0080);
+
+ break;
+ }
+#endif
+ case 21:
+ {
+ info = (void*)&id21;
+ status = get_user_info_21(&id21, rid) ? 0 : NT_STATUS_NO_SUCH_USER;
+ break;
+ }
+
+ default:
+ {
+ status = NT_STATUS_INVALID_INFO_CLASS;
+
+ break;
+ }
+ }
+ }
+
+ make_samr_r_query_userinfo(&r_u, q_u->switch_value, info, status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_query_userinfo("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_reply_query_userinfo: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_query_userinfo
+ ********************************************************************/
+static void api_samr_query_userinfo( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_QUERY_USERINFO q_u;
+
+ /* grab the samr unknown 24 */
+ samr_io_q_query_userinfo("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_query_userinfo(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_query_usergroups
+ ********************************************************************/
+static void samr_reply_query_usergroups(SAMR_Q_QUERY_USERGROUPS *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_QUERY_USERGROUPS r_u;
+ uint32 status = 0x0;
+
+ struct sam_passwd *sam_pass;
+ DOM_GID *gids = NULL;
+ int num_groups = 0;
+ uint32 rid;
+
+ DEBUG(5,("samr_query_usergroups: %d\n", __LINE__));
+
+ /* find the policy handle. open a policy on it. */
+ if (status == 0x0 && (find_lsa_policy_by_hnd(&(q_u->pol)) == -1))
+ {
+ status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* find the user's rid */
+ if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->pol))) == 0xffffffff)
+ {
+ status = NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (status == 0x0)
+ {
+ become_root(True);
+ sam_pass = getsam21pwrid(rid);
+ unbecome_root(True);
+
+ if (sam_pass == NULL)
+ {
+ status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
+ if (status == 0x0)
+ {
+ pstring groups;
+ get_domain_user_groups(groups, sam_pass->smb_name);
+ gids = NULL;
+ num_groups = make_dom_gids(groups, &gids);
+ }
+
+ /* construct the response. lkclXXXX: gids are not copied! */
+ make_samr_r_query_usergroups(&r_u, num_groups, gids, status);
+
+ /* store the response in the SMB stream */
+ samr_io_r_query_usergroups("", &r_u, rdata, 0);
+
+ if (gids)
+ {
+ free((char *)gids);
+ }
+
+ DEBUG(5,("samr_query_usergroups: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_query_usergroups
+ ********************************************************************/
+static void api_samr_query_usergroups( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_QUERY_USERGROUPS q_u;
+ /* grab the samr unknown 32 */
+ samr_io_q_query_usergroups("", &q_u, data, 0);
+
+ /* construct reply. */
+ samr_reply_query_usergroups(&q_u, rdata);
+}
+
+
+/*******************************************************************
+ samr_reply_unknown_32
+ ********************************************************************/
+static void samr_reply_unknown_32(SAMR_Q_UNKNOWN_32 *q_u,
+ prs_struct *rdata,
+ int status)
+{
+ int i;
+ SAMR_R_UNKNOWN_32 r_u;
+
+ /* set up the SAMR unknown_32 response */
+ bzero(r_u.pol.data, POL_HND_SIZE);
+ if (status == 0)
+ {
+ for (i = 4; i < POL_HND_SIZE; i++)
+ {
+ r_u.pol.data[i] = i+1;
+ }
+ }
+
+ make_dom_rid4(&(r_u.rid4), 0x0030, 0, 0);
+ r_u.status = status;
+
+ DEBUG(5,("samr_unknown_32: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_unknown_32("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_unknown_32: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_unknown_32
+ ********************************************************************/
+static void api_samr_unknown_32( int uid, prs_struct *data, prs_struct *rdata)
+{
+ uint32 status = 0;
+ struct sam_passwd *sam_pass;
+ fstring mach_acct;
+
+ SAMR_Q_UNKNOWN_32 q_u;
+
+ /* grab the samr unknown 32 */
+ samr_io_q_unknown_32("", &q_u, data, 0);
+
+ /* find the machine 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...
+ */
+
+ fstrcpy(mach_acct, unistrn2(q_u.uni_mach_acct.buffer,
+ q_u.uni_mach_acct.uni_str_len));
+
+ become_root(True);
+ sam_pass = getsam21pwnam(mach_acct);
+ unbecome_root(True);
+
+ if (sam_pass != NULL)
+ {
+ /* machine account exists: say so */
+ status = 0xC0000000 | NT_STATUS_USER_EXISTS;
+ }
+ else
+ {
+ /* this could cause trouble... */
+ DEBUG(0,("trouble!\n"));
+ status = 0;
+ }
+
+ /* construct reply. */
+ samr_reply_unknown_32(&q_u, rdata, status);
+}
+
+
+/*******************************************************************
+ samr_reply_connect
+ ********************************************************************/
+static void samr_reply_connect(SAMR_Q_CONNECT *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_CONNECT r_u;
+ BOOL pol_open = False;
+
+ /* set up the SAMR connect response */
+
+ r_u.status = 0x0;
+ /* get a (unique) handle. open a policy on it. */
+ if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.connect_pol))))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* associate the domain SID with the (unique) handle. */
+ if (r_u.status == 0x0 && !set_lsa_policy_samr_pol_status(&(r_u.connect_pol), q_u->unknown_0))
+ {
+ /* oh, whoops. don't know what error message to return, here */
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (r_u.status != 0 && pol_open)
+ {
+ close_lsa_policy_hnd(&(r_u.connect_pol));
+ }
+
+ DEBUG(5,("samr_connect: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_connect("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_connect: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_connect
+ ********************************************************************/
+static void api_samr_connect( int uid, prs_struct *data, prs_struct *rdata)
+{
+ SAMR_Q_CONNECT q_u;
+
+ /* grab the samr open policy */
+ samr_io_q_connect("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_connect(&q_u, rdata);
+}
+
+/*******************************************************************
+ samr_reply_open_alias
+ ********************************************************************/
+static void samr_reply_open_alias(SAMR_Q_OPEN_ALIAS *q_u,
+ prs_struct *rdata)
+{
+ SAMR_R_OPEN_ALIAS r_u;
+ BOOL pol_open = False;
+
+ /* set up the SAMR open_alias response */
+
+ r_u.status = 0x0;
+ /* get a (unique) handle. open a policy on it. */
+ if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.pol))))
+ {
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* associate a RID with the (unique) handle. */
+ if (r_u.status == 0x0 && !set_lsa_policy_samr_rid(&(r_u.pol), q_u->rid_alias))
+ {
+ /* oh, whoops. don't know what error message to return, here */
+ r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ if (r_u.status != 0 && pol_open)
+ {
+ close_lsa_policy_hnd(&(r_u.pol));
+ }
+
+ DEBUG(5,("samr_open_alias: %d\n", __LINE__));
+
+ /* store the response in the SMB stream */
+ samr_io_r_open_alias("", &r_u, rdata, 0);
+
+ DEBUG(5,("samr_open_alias: %d\n", __LINE__));
+
+}
+
+/*******************************************************************
+ api_samr_open_alias
+ ********************************************************************/
+static void api_samr_open_alias( int uid, prs_struct *data, prs_struct *rdata)
+
+{
+ SAMR_Q_OPEN_ALIAS q_u;
+
+ /* grab the samr open policy */
+ samr_io_q_open_alias("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ samr_reply_open_alias(&q_u, rdata);
+}
+
+/*******************************************************************
+ 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_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_LOOKUP_IDS" , SAMR_LOOKUP_IDS , api_samr_lookup_ids },
+ { "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_QUERY_USERGROUPS" , SAMR_QUERY_USERGROUPS , api_samr_query_usergroups },
+ { "SAMR_QUERY_DISPINFO" , SAMR_QUERY_DISPINFO , api_samr_query_dispinfo },
+ { "SAMR_QUERY_ALIASINFO" , SAMR_QUERY_ALIASINFO , api_samr_query_aliasinfo },
+ { "SAMR_0x32" , 0x32 , api_samr_unknown_32 },
+ { "SAMR_UNKNOWN_12" , SAMR_UNKNOWN_12 , api_samr_unknown_12 },
+ { "SAMR_OPEN_ALIAS" , SAMR_OPEN_ALIAS , api_samr_open_alias },
+ { "SAMR_OPEN_DOMAIN" , SAMR_OPEN_DOMAIN , api_samr_open_domain },
+ { "SAMR_UNKNOWN_3" , SAMR_UNKNOWN_3 , api_samr_unknown_3 },
+ { NULL , 0 , NULL }
+};
+
+/*******************************************************************
+ receives a samr pipe and responds.
+ ********************************************************************/
+BOOL api_samr_rpc(pipes_struct *p, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_samr_rpc", api_samr_cmds, data);
+}
+
diff --git a/source/rpc_server/srv_srvsvc.c b/source/rpc_server/srv_srvsvc.c
new file mode 100644
index 00000000000..a4ae3fa0efe
--- /dev/null
+++ b/source/rpc_server/srv_srvsvc.c
@@ -0,0 +1,1066 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern pstring global_myname;
+
+/*******************************************************************
+ fill in a share info level 1 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ see ipc.c:fill_share_info()
+
+ ********************************************************************/
+static void make_srv_share_1_info(SH_INFO_1 *sh1,
+ SH_INFO_1_STR *str1, int snum)
+{
+ int len_net_name;
+ pstring net_name;
+ pstring remark;
+ uint32 type;
+
+ pstrcpy(net_name, lp_servicename(snum));
+ pstrcpy(remark , lp_comment (snum));
+ 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;
+
+ make_srv_share_info1 (sh1 , net_name, type, remark);
+ make_srv_share_info1_str(str1, net_name, remark);
+}
+
+/*******************************************************************
+ fill in a share info level 1 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_srv_share_info_1(SRV_SHARE_INFO_1 *sh1, uint32 *snum, uint32 *svcs)
+{
+ uint32 num_entries = 0;
+ (*svcs) = lp_numservices();
+
+ if (sh1 == NULL)
+ {
+ (*snum) = 0;
+ return;
+ }
+
+ DEBUG(5,("make_srv_share_1_sh1\n"));
+
+ for (; (*snum) < (*svcs) && num_entries < MAX_SHARE_ENTRIES; (*snum)++)
+ {
+ if (lp_browseable((*snum)) && lp_snum_ok((*snum)))
+ {
+ make_srv_share_1_info(&(sh1->info_1 [num_entries]),
+ &(sh1->info_1_str[num_entries]), (*snum));
+
+ /* move on to creating next share */
+ num_entries++;
+ }
+ }
+
+ sh1->num_entries_read = num_entries;
+ sh1->ptr_share_info = num_entries > 0 ? 1 : 0;
+ sh1->num_entries_read2 = num_entries;
+
+ if ((*snum) >= (*svcs))
+ {
+ (*snum) = 0;
+ }
+}
+
+/*******************************************************************
+ fill in a share info level 2 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ see ipc.c:fill_share_info()
+
+ ********************************************************************/
+static void make_srv_share_2_info(SH_INFO_2 *sh2,
+ SH_INFO_2_STR *str2, 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));
+ pstrcpy(path , lp_pathname (snum));
+ 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;
+
+ make_srv_share_info2 (sh2 , net_name, type, remark, 0, 0xffffffff, 1, path, passwd);
+ make_srv_share_info2_str(str2, net_name, remark, path, passwd);
+}
+
+/*******************************************************************
+ fill in a share info level 2 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_srv_share_info_2(SRV_SHARE_INFO_2 *sh2, uint32 *snum, uint32 *svcs)
+{
+ uint32 num_entries = 0;
+ (*svcs) = lp_numservices();
+
+ if (sh2 == NULL)
+ {
+ (*snum) = 0;
+ return;
+ }
+
+ DEBUG(5,("make_srv_share_2_sh1\n"));
+
+ for (; (*snum) < (*svcs) && num_entries < MAX_SHARE_ENTRIES; (*snum)++)
+ {
+ if (lp_browseable((*snum)) && lp_snum_ok((*snum)))
+ {
+ make_srv_share_2_info(&(sh2->info_2 [num_entries]),
+ &(sh2->info_2_str[num_entries]), (*snum));
+
+ /* move on to creating next share */
+ num_entries++;
+ }
+ }
+
+ sh2->num_entries_read = num_entries;
+ sh2->ptr_share_info = num_entries > 0 ? 1 : 0;
+ sh2->num_entries_read2 = num_entries;
+
+ if ((*snum) >= (*svcs))
+ {
+ (*snum) = 0;
+ }
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_SHARE_ENUM structure.
+********************************************************************/
+static uint32 make_srv_share_info_ctr(SRV_SHARE_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ uint32 status = 0x0;
+ DEBUG(5,("make_srv_share_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value)
+ {
+ case 1:
+ {
+ make_srv_share_info_1(&(ctr->share.info1), resume_hnd, total_entries);
+ ctr->ptr_share_ctr = 1;
+ break;
+ }
+ case 2:
+ {
+ make_srv_share_info_2(&(ctr->share.info2), resume_hnd, total_entries);
+ ctr->ptr_share_ctr = 2;
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("make_srv_share_info_ctr: unsupported switch value %d\n",
+ switch_value));
+ (*resume_hnd = 0);
+ (*total_entries) = 0;
+ ctr->ptr_share_ctr = 0;
+ status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_SHARE_ENUM structure.
+********************************************************************/
+static void make_srv_r_net_share_enum(SRV_R_NET_SHARE_ENUM *r_n,
+ uint32 resume_hnd, int share_level, int switch_value)
+{
+ DEBUG(5,("make_srv_r_net_share_enum: %d\n", __LINE__));
+
+ r_n->share_level = share_level;
+ if (share_level == 0)
+ {
+ r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ }
+ else
+ {
+ r_n->status = make_srv_share_info_ctr(r_n->ctr, switch_value, &resume_hnd, &(r_n->total_entries));
+ }
+ if (r_n->status != 0x0)
+ {
+ resume_hnd = 0;
+ }
+ make_enum_hnd(&(r_n->enum_hnd), resume_hnd);
+}
+
+/*******************************************************************
+net share enum
+********************************************************************/
+static void srv_reply_net_share_enum(SRV_Q_NET_SHARE_ENUM *q_n,
+ prs_struct *rdata)
+{
+ SRV_R_NET_SHARE_ENUM r_n;
+ SRV_SHARE_INFO_CTR ctr;
+
+ r_n.ctr = &ctr;
+
+ DEBUG(5,("srv_net_share_enum: %d\n", __LINE__));
+
+ /* set up the */
+ make_srv_r_net_share_enum(&r_n,
+ get_enum_hnd(&q_n->enum_hnd),
+ q_n->share_level,
+ q_n->ctr->switch_value);
+
+ /* store the response in the SMB stream */
+ srv_io_r_net_share_enum("", &r_n, rdata, 0);
+
+ DEBUG(5,("srv_net_share_enum: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ fill in a sess info level 1 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_srv_sess_0_info(SESS_INFO_0 *se0, SESS_INFO_0_STR *str0,
+ char *name)
+{
+ make_srv_sess_info0 (se0 , name);
+ make_srv_sess_info0_str(str0, name);
+}
+
+/*******************************************************************
+ fill in a sess info level 0 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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,("make_srv_sess_0_ss0\n"));
+
+ if (snum)
+ {
+ for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++)
+ {
+ make_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.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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)
+{
+ make_srv_sess_info1 (se1 , name, user, num_opens, open_time, idle_time, usr_flgs);
+ make_srv_sess_info1_str(str1, name, user);
+}
+
+/*******************************************************************
+ fill in a sess info level 1 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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,("make_srv_sess_1_ss1\n"));
+
+ if (snum)
+ {
+ for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++)
+ {
+ make_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 uint32 make_srv_sess_info_ctr(SRV_SESS_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ uint32 status = 0x0;
+ DEBUG(5,("make_srv_sess_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value)
+ {
+ case 0:
+ {
+ make_srv_sess_info_0(&(ctr->sess.info0), resume_hnd, total_entries);
+ ctr->ptr_sess_ctr = 1;
+ break;
+ }
+ case 1:
+ {
+ make_srv_sess_info_1(&(ctr->sess.info1), resume_hnd, total_entries);
+ ctr->ptr_sess_ctr = 1;
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("make_srv_sess_info_ctr: unsupported switch value %d\n",
+ switch_value));
+ (*resume_hnd) = 0;
+ (*total_entries) = 0;
+ ctr->ptr_sess_ctr = 0;
+ status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_SESS_ENUM structure.
+********************************************************************/
+static void make_srv_r_net_sess_enum(SRV_R_NET_SESS_ENUM *r_n,
+ uint32 resume_hnd, int sess_level, int switch_value)
+{
+ DEBUG(5,("make_srv_r_net_sess_enum: %d\n", __LINE__));
+
+ r_n->sess_level = sess_level;
+ if (sess_level == -1)
+ {
+ r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ }
+ else
+ {
+ r_n->status = make_srv_sess_info_ctr(r_n->ctr, switch_value, &resume_hnd, &r_n->total_entries);
+ }
+ if (r_n->status != 0x0)
+ {
+ resume_hnd = 0;
+ }
+ make_enum_hnd(&(r_n->enum_hnd), resume_hnd);
+}
+
+/*******************************************************************
+net sess enum
+********************************************************************/
+static void srv_reply_net_sess_enum(SRV_Q_NET_SESS_ENUM *q_n,
+ prs_struct *rdata)
+{
+ SRV_R_NET_SESS_ENUM r_n;
+ SRV_SESS_INFO_CTR ctr;
+
+ r_n.ctr = &ctr;
+
+ DEBUG(5,("srv_net_sess_enum: %d\n", __LINE__));
+
+ /* set up the */
+ make_srv_r_net_sess_enum(&r_n,
+ get_enum_hnd(&q_n->enum_hnd),
+ q_n->sess_level,
+ q_n->ctr->switch_value);
+
+ /* store the response in the SMB stream */
+ srv_io_r_net_sess_enum("", &r_n, rdata, 0);
+
+ DEBUG(5,("srv_net_sess_enum: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ fill in a conn info level 0 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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,("make_srv_conn_0_ss0\n"));
+
+ if (snum)
+ {
+ for (; (*snum) < (*stot) && num_entries < MAX_CONN_ENTRIES; (*snum)++)
+ {
+ make_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.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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)
+{
+ make_srv_conn_info1 (se1 , id, type, num_opens, num_users, open_time, usr_name, net_name);
+ make_srv_conn_info1_str(str1, usr_name, net_name);
+}
+
+/*******************************************************************
+ fill in a conn info level 1 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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,("make_srv_conn_1_ss1\n"));
+
+ if (snum)
+ {
+ for (; (*snum) < (*stot) && num_entries < MAX_CONN_ENTRIES; (*snum)++)
+ {
+ make_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 uint32 make_srv_conn_info_ctr(SRV_CONN_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ uint32 status = 0x0;
+ DEBUG(5,("make_srv_conn_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value)
+ {
+ case 0:
+ {
+ make_srv_conn_info_0(&(ctr->conn.info0), resume_hnd, total_entries);
+ ctr->ptr_conn_ctr = 1;
+ break;
+ }
+ case 1:
+ {
+ make_srv_conn_info_1(&(ctr->conn.info1), resume_hnd, total_entries);
+ ctr->ptr_conn_ctr = 1;
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("make_srv_conn_info_ctr: unsupported switch value %d\n",
+ switch_value));
+ (*resume_hnd = 0);
+ (*total_entries) = 0;
+ ctr->ptr_conn_ctr = 0;
+ status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_CONN_ENUM structure.
+********************************************************************/
+static void make_srv_r_net_conn_enum(SRV_R_NET_CONN_ENUM *r_n,
+ uint32 resume_hnd, int conn_level, int switch_value)
+{
+ DEBUG(5,("make_srv_r_net_conn_enum: %d\n", __LINE__));
+
+ r_n->conn_level = conn_level;
+ if (conn_level == -1)
+ {
+ r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ }
+ else
+ {
+ r_n->status = make_srv_conn_info_ctr(r_n->ctr, switch_value, &resume_hnd, &r_n->total_entries);
+ }
+ if (r_n->status != 0x0)
+ {
+ resume_hnd = 0;
+ }
+ make_enum_hnd(&(r_n->enum_hnd), resume_hnd);
+}
+
+/*******************************************************************
+net conn enum
+********************************************************************/
+static void srv_reply_net_conn_enum(SRV_Q_NET_CONN_ENUM *q_n,
+ prs_struct *rdata)
+{
+ SRV_R_NET_CONN_ENUM r_n;
+ SRV_CONN_INFO_CTR ctr;
+
+ r_n.ctr = &ctr;
+
+ DEBUG(5,("srv_net_conn_enum: %d\n", __LINE__));
+
+ /* set up the */
+ make_srv_r_net_conn_enum(&r_n,
+ get_enum_hnd(&q_n->enum_hnd),
+ q_n->conn_level,
+ q_n->ctr->switch_value);
+
+ /* store the response in the SMB stream */
+ srv_io_r_net_conn_enum("", &r_n, rdata, 0);
+
+ DEBUG(5,("srv_net_conn_enum: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ fill in a file info level 3 structure.
+ ********************************************************************/
+static void make_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)
+{
+ make_srv_file_info3 (fl3 , fnum, perms, num_locks, path_name, user_name);
+ make_srv_file_info3_str(str3, path_name, user_name);
+}
+
+/*******************************************************************
+ fill in a file info level 3 structure.
+
+ this function breaks the rule that i'd like to be in place, namely
+ it doesn't receive its data as arguments: it has to call lp_xxxx()
+ functions itself. yuck.
+
+ ********************************************************************/
+static void make_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,("make_srv_file_3_fl3\n"));
+
+ for (; (*fnum) < (*ftot) && num_entries < MAX_FILE_ENTRIES; (*fnum)++)
+ {
+ make_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 uint32 make_srv_file_info_ctr(SRV_FILE_INFO_CTR *ctr,
+ int switch_value, uint32 *resume_hnd, uint32 *total_entries)
+{
+ uint32 status = 0x0;
+ DEBUG(5,("make_srv_file_info_ctr: %d\n", __LINE__));
+
+ ctr->switch_value = switch_value;
+
+ switch (switch_value)
+ {
+ case 3:
+ {
+ make_srv_file_info_3(&(ctr->file.info3), resume_hnd, total_entries);
+ ctr->ptr_file_ctr = 1;
+ break;
+ }
+ default:
+ {
+ DEBUG(5,("make_srv_file_info_ctr: unsupported switch value %d\n",
+ switch_value));
+ (*resume_hnd = 0);
+ (*total_entries) = 0;
+ ctr->ptr_file_ctr = 0;
+ status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************
+ makes a SRV_R_NET_FILE_ENUM structure.
+********************************************************************/
+static void make_srv_r_net_file_enum(SRV_R_NET_FILE_ENUM *r_n,
+ uint32 resume_hnd, int file_level, int switch_value)
+{
+ DEBUG(5,("make_srv_r_net_file_enum: %d\n", __LINE__));
+
+ r_n->file_level = file_level;
+ if (file_level == 0)
+ {
+ r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ }
+ else
+ {
+ r_n->status = make_srv_file_info_ctr(r_n->ctr, switch_value, &resume_hnd, &(r_n->total_entries));
+ }
+ if (r_n->status != 0x0)
+ {
+ resume_hnd = 0;
+ }
+ make_enum_hnd(&(r_n->enum_hnd), resume_hnd);
+}
+
+/*******************************************************************
+net file enum
+********************************************************************/
+static void srv_reply_net_file_enum(SRV_Q_NET_FILE_ENUM *q_n,
+ prs_struct *rdata)
+{
+ SRV_R_NET_FILE_ENUM r_n;
+ SRV_FILE_INFO_CTR ctr;
+
+ r_n.ctr = &ctr;
+
+ DEBUG(5,("srv_net_file_enum: %d\n", __LINE__));
+
+ /* set up the */
+ make_srv_r_net_file_enum(&r_n,
+ get_enum_hnd(&q_n->enum_hnd),
+ q_n->file_level,
+ q_n->ctr->switch_value);
+
+ /* store the response in the SMB stream */
+ srv_io_r_net_file_enum("", &r_n, rdata, 0);
+
+ DEBUG(5,("srv_net_file_enum: %d\n", __LINE__));
+}
+
+/*******************************************************************
+net server get info
+********************************************************************/
+static void srv_reply_net_srv_get_info(SRV_Q_NET_SRV_GET_INFO *q_n,
+ prs_struct *rdata)
+{
+ SRV_R_NET_SRV_GET_INFO r_n;
+ uint32 status = 0x0;
+ SRV_INFO_CTR ctr;
+
+
+ DEBUG(5,("srv_net_srv_get_info: %d\n", __LINE__));
+
+ switch (q_n->switch_value)
+ {
+ case 102:
+ {
+ make_srv_info_102(&ctr.srv.sv102,
+ 500, global_myname, lp_serverstring(),
+ 5, 4, /* major/minor version - NT 5.4 :-) */
+ 0x4100b, /* browsing stuff SV_TYPE_XXXX */
+ 0xffffffff, /* users */
+ 0xf, /* disc */
+ 0, /* hidden */
+ 240, /* announce */
+ 3000, /* announce delta */
+ 100000, /* licenses */
+ "c:\\"); /* user path */
+ break;
+ }
+ case 101:
+ {
+ make_srv_info_101(&ctr.srv.sv101,
+ 500, global_myname,
+ 5, 4, /* major/minor version - NT 5.4 :-) */
+ 0x4100b, /* browsing stuff SV_TYPE_XXXX */
+ lp_serverstring());
+ break;
+ }
+ default:
+ {
+ status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+ }
+
+ /* set up the net server get info structure */
+ make_srv_r_net_srv_get_info(&r_n, q_n->switch_value, &ctr, status);
+
+ /* store the response in the SMB stream */
+ srv_io_r_net_srv_get_info("", &r_n, rdata, 0);
+
+ DEBUG(5,("srv_net_srv_get_info: %d\n", __LINE__));
+}
+
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_srv_get_info( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ SRV_Q_NET_SRV_GET_INFO q_n;
+
+ /* grab the net server get info */
+ srv_io_q_net_srv_get_info("", &q_n, data, 0);
+
+ /* construct reply. always indicate success */
+ srv_reply_net_srv_get_info(&q_n, rdata);
+}
+
+
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_file_enum( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ SRV_Q_NET_FILE_ENUM q_n;
+ SRV_FILE_INFO_CTR ctr;
+
+ q_n.ctr = &ctr;
+
+ /* grab the net file enum */
+ srv_io_q_net_file_enum("", &q_n, data, 0);
+
+ /* construct reply. always indicate success */
+ srv_reply_net_file_enum(&q_n, rdata);
+}
+
+
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_conn_enum( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ SRV_Q_NET_CONN_ENUM q_n;
+ SRV_CONN_INFO_CTR ctr;
+
+ q_n.ctr = &ctr;
+
+ /* grab the net server get enum */
+ srv_io_q_net_conn_enum("", &q_n, data, 0);
+
+ /* construct reply. always indicate success */
+ srv_reply_net_conn_enum(&q_n, rdata);
+}
+
+
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_sess_enum( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ SRV_Q_NET_SESS_ENUM q_n;
+ SRV_SESS_INFO_CTR ctr;
+
+ q_n.ctr = &ctr;
+
+ /* grab the net server get enum */
+ srv_io_q_net_sess_enum("", &q_n, data, 0);
+
+ /* construct reply. always indicate success */
+ srv_reply_net_sess_enum(&q_n, rdata);
+}
+
+
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_share_enum( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ SRV_Q_NET_SHARE_ENUM q_n;
+ SRV_SHARE_INFO_CTR ctr;
+
+ q_n.ctr = &ctr;
+
+ /* grab the net server get enum */
+ srv_io_q_net_share_enum("", &q_n, data, 0);
+
+ /* construct reply. always indicate success */
+ srv_reply_net_share_enum(&q_n, rdata);
+}
+
+/*******************************************************************
+time of day
+********************************************************************/
+static void srv_reply_net_remote_tod(SRV_Q_NET_REMOTE_TOD *q_n,
+ prs_struct *rdata)
+{
+ SRV_R_NET_REMOTE_TOD r_n;
+ TIME_OF_DAY_INFO tod;
+ struct tm *t;
+ time_t unixdate = time(NULL);
+
+ r_n.tod = &tod;
+ r_n.ptr_srv_tod = 0x1;
+ r_n.status = 0x0;
+
+ DEBUG(5,("srv_reply_net_remote_tod: %d\n", __LINE__));
+
+ t = gmtime(&unixdate);
+
+ /* set up the */
+ make_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);
+
+ /* store the response in the SMB stream */
+ srv_io_r_net_remote_tod("", &r_n, rdata, 0);
+
+ DEBUG(5,("srv_reply_net_remote_tod: %d\n", __LINE__));
+}
+/*******************************************************************
+********************************************************************/
+static void api_srv_net_remote_tod( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ SRV_Q_NET_REMOTE_TOD q_n;
+
+ /* grab the net server get enum */
+ srv_io_q_net_remote_tod("", &q_n, data, 0);
+
+ /* construct reply. always indicate success */
+ srv_reply_net_remote_tod(&q_n, rdata);
+}
+
+
+/*******************************************************************
+\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" , SRV_NETSHAREENUM , api_srv_net_share_enum },
+ { "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_REMOTE_TOD" , SRV_NET_REMOTE_TOD , api_srv_net_remote_tod },
+ { NULL , 0 , NULL }
+};
+
+/*******************************************************************
+receives a srvsvc pipe and responds.
+********************************************************************/
+BOOL api_srvsvc_rpc(pipes_struct *p, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_srvsvc_rpc", api_srv_cmds, data);
+}
+
diff --git a/source/rpc_server/srv_util.c b/source/rpc_server/srv_util.c
new file mode 100644
index 00000000000..3c0fc9271e4
--- /dev/null
+++ b/source/rpc_server/srv_util.c
@@ -0,0 +1,496 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern DOM_SID global_machine_sid;
+
+/*
+ * 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 }
+};
+
+int make_dom_gids(char *gids_str, DOM_GID **ppgids)
+{
+ char *ptr;
+ pstring s2;
+ int count;
+ DOM_GID *gids;
+
+ *ppgids = NULL;
+
+ DEBUG(4,("make_dom_gids: %s\n", gids_str));
+
+ if (gids_str == NULL || *gids_str == 0)
+ return 0;
+
+ for (count = 0, ptr = gids_str;
+ next_token(&ptr, s2, NULL, sizeof(s2));
+ count++)
+ ;
+
+ gids = (DOM_GID *)malloc( sizeof(DOM_GID) * count );
+ if(!gids)
+ {
+ DEBUG(0,("make_dom_gids: malloc fail !\n"));
+ return 0;
+ }
+
+ for (count = 0, ptr = gids_str;
+ next_token(&ptr, s2, NULL, sizeof(s2)) &&
+ count < LSA_MAX_GROUPS;
+ count++)
+ {
+ /* the entries are of the form GID/ATTR, ATTR being optional.*/
+ char *attr;
+ uint32 rid = 0;
+ int i;
+
+ attr = strchr(s2,'/');
+ if (attr)
+ *attr++ = 0;
+
+ if (!attr || !*attr)
+ attr = "7"; /* default value for attribute is 7 */
+
+ /* look up the RID string and see if we can turn it into a rid number */
+ for (i = 0; builtin_alias_rids[i].name != NULL; i++)
+ {
+ if (strequal(builtin_alias_rids[i].name, s2))
+ {
+ rid = builtin_alias_rids[i].rid;
+ break;
+ }
+ }
+
+ if (rid == 0)
+ rid = atoi(s2);
+
+ if (rid == 0)
+ {
+ DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n", s2, attr));
+ count--;
+ }
+ else
+ {
+ gids[count].g_rid = rid;
+ gids[count].attr = atoi(attr);
+
+ DEBUG(5,("group id: %d attr: %d\n", gids[count].g_rid, gids[count].attr));
+ }
+ }
+
+ *ppgids = gids;
+ return count;
+}
+
+/*******************************************************************
+ turns a DCE/RPC request into a DCE/RPC reply
+
+ this is where the data really should be split up into an array of
+ headers and data sections.
+
+ ********************************************************************/
+BOOL create_rpc_reply(pipes_struct *p,
+ uint32 data_start, uint32 data_end)
+{
+ DEBUG(5,("create_rpc_reply: data_start: %d data_end: %d max_tsize: %d\n",
+ data_start, data_end, p->hdr_ba.bba.max_tsize));
+
+ mem_buf_init(&(p->rhdr.data), 0);
+ mem_alloc_data(p->rhdr.data, 0x18);
+
+ p->rhdr.align = 4;
+ p->rhdr.io = False;
+
+ p->hdr_resp.alloc_hint = data_end - data_start; /* calculate remaining data to be sent */
+ p->hdr.pkt_type = RPC_RESPONSE; /* mark header as an rpc response */
+
+ /* set up rpc header (fragmentation issues) */
+ if (data_start == 0)
+ {
+ p->hdr.flags = RPC_FLG_FIRST;
+ }
+ else
+ {
+ p->hdr.flags = 0;
+ }
+
+ if (p->hdr_resp.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize)
+ {
+ p->hdr.flags |= RPC_FLG_LAST;
+ p->hdr.frag_len = p->hdr_resp.alloc_hint + 0x18;
+ }
+ else
+ {
+ p->hdr.frag_len = p->hdr_ba.bba.max_tsize;
+ }
+
+ p->rhdr.data->offset.start = 0;
+ p->rhdr.data->offset.end = 0x18;
+
+ /* store the header in the data stream */
+ p->rhdr.offset = 0;
+ smb_io_rpc_hdr ("hdr", &(p->hdr ), &(p->rhdr), 0);
+ smb_io_rpc_hdr_resp("resp", &(p->hdr_resp), &(p->rhdr), 0);
+
+ return p->rhdr.data != NULL && p->rhdr.offset == 0x18;
+}
+
+
+/*******************************************************************
+ receives a netlogon pipe and responds.
+ ********************************************************************/
+static BOOL api_rpc_command(pipes_struct *p,
+ char *rpc_name, struct api_struct *api_rpc_cmds,
+ prs_struct *data)
+{
+ int fn_num;
+ DEBUG(4,("api_rpc_command: %s op 0x%x - ", rpc_name, p->hdr_req.opnum));
+
+ 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_rpc_command: %s\n", api_rpc_cmds[fn_num].name));
+ break;
+ }
+ }
+
+ if (api_rpc_cmds[fn_num].name == NULL)
+ {
+ DEBUG(4, ("unknown\n"));
+ return False;
+ }
+
+ /* start off with 1024 bytes, and a large safety margin too */
+ mem_buf_init(&(p->rdata.data), SAFETY_MARGIN);
+ mem_alloc_data(p->rdata.data, 1024);
+
+ p->rdata.io = False;
+ p->rdata.align = 4;
+
+ p->rdata.data->offset.start = 0;
+ p->rdata.data->offset.end = 0xffffffff;
+
+ /* do the actual command */
+ p->rdata.offset = 0;
+ api_rpc_cmds[fn_num].fn(p->uid, data, &(p->rdata));
+
+ if (p->rdata.data == NULL || p->rdata.offset == 0)
+ {
+ mem_free_data(p->rdata.data);
+ return False;
+ }
+
+ mem_realloc_data(p->rdata.data, p->rdata.offset);
+
+ DEBUG(10,("called %s\n", rpc_name));
+
+ return True;
+}
+
+
+/*******************************************************************
+ receives a netlogon pipe and responds.
+ ********************************************************************/
+BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds,
+ prs_struct *data)
+{
+ if (data == NULL || data->data == NULL)
+ {
+ DEBUG(2,("%s: NULL data received\n", rpc_name));
+ return False;
+ }
+
+ /* read the rpc header */
+ smb_io_rpc_hdr_req("req", &(p->hdr_req), data, 0);
+
+ /* interpret the command */
+ if (!api_rpc_command(p, rpc_name, api_rpc_cmds, data))
+ {
+ return False;
+ }
+
+ /* create the rpc header */
+ if (!create_rpc_reply(p, 0, p->rdata.offset))
+ {
+ return False;
+ }
+
+ p->frag_len_left = p->hdr.frag_len - p->file_offset;
+ p->next_frag_start = p->hdr.frag_len;
+
+ /* set up the data chain */
+ p->rhdr.data->offset.start = 0;
+ p->rhdr.data->offset.end = p->rhdr.offset;
+ p->rhdr.data->next = p->rdata.data;
+
+ p->rdata.data->offset.start = p->rhdr.data->offset.end;
+ p->rdata.data->offset.end = p->rhdr.data->offset.end + p->rdata.offset;
+ p->rdata.data->next = NULL;
+
+ return True;
+}
+
+
+/*******************************************************************
+ gets a domain user's groups
+ ********************************************************************/
+void get_domain_user_groups(char *domain_groups, char *user)
+{
+ pstring tmp;
+
+ if (domain_groups == NULL || user == NULL) return;
+
+ /* any additional groups this user is in. e.g power users */
+ pstrcpy(domain_groups, lp_domain_groups());
+
+ /* can only be a user or a guest. cannot be guest _and_ admin */
+ if (user_in_list(user, lp_domain_guest_group()))
+ {
+ slprintf(tmp, sizeof(tmp) - 1, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS);
+ pstrcat(domain_groups, tmp);
+
+ DEBUG(3,("domain guest group access %s granted\n", tmp));
+ }
+ else
+ {
+ slprintf(tmp, sizeof(tmp) -1, " %ld/7 ", DOMAIN_GROUP_RID_USERS);
+ pstrcat(domain_groups, tmp);
+
+ DEBUG(3,("domain group access %s granted\n", tmp));
+
+ if (user_in_list(user, lp_domain_admin_group()))
+ {
+ slprintf(tmp, sizeof(tmp) - 1, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS);
+ pstrcat(domain_groups, tmp);
+
+ DEBUG(3,("domain admin group access %s granted\n", tmp));
+ }
+ }
+}
+
+
+/*******************************************************************
+ lookup_group_name
+ ********************************************************************/
+uint32 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 0x0;
+ }
+
+ DEBUG(5,(" none mapped\n"));
+ return 0xC0000000 | NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ lookup_alias_name
+ ********************************************************************/
+uint32 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 0x0;
+ }
+
+ DEBUG(5,(" none mapped\n"));
+ return 0xC0000000 | NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ lookup_user_name
+ ********************************************************************/
+uint32 lookup_user_name(uint32 rid, char *user_name, uint32 *type)
+{
+ struct sam_disp_info *disp_info;
+ int i = 0;
+ (*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 0x0;
+ }
+
+ /* ok, it's a user. find the user account */
+ become_root(True);
+ disp_info = getsamdisprid(rid);
+ unbecome_root(True);
+
+ if (disp_info != NULL)
+ {
+ fstrcpy(user_name, disp_info->smb_name);
+ DEBUG(5,(" = %s\n", user_name));
+ return 0x0;
+ }
+
+ DEBUG(5,(" none mapped\n"));
+ return 0xC0000000 | NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ lookup_group_rid
+ ********************************************************************/
+uint32 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) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ lookup_alias_rid
+ ********************************************************************/
+uint32 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) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED;
+}
+
+/*******************************************************************
+ lookup_user_rid
+ ********************************************************************/
+uint32 lookup_user_rid(char *user_name, uint32 *rid)
+{
+ struct sam_passwd *sam_pass;
+ (*rid) = 0;
+
+ /* find the user account */
+ become_root(True);
+ sam_pass = getsam21pwnam(user_name);
+ unbecome_root(True);
+
+ if (sam_pass != NULL)
+ {
+ (*rid) = sam_pass->user_rid;
+ return 0x0;
+ }
+
+ return 0xC0000000 | 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..5bea006b2cd
--- /dev/null
+++ b/source/rpc_server/srv_wkssvc.c
@@ -0,0 +1,112 @@
+
+/*
+ * 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+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);
+
+ make_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.
+
+ ********************************************************************/
+static void wks_reply_query_info(WKS_Q_QUERY_INFO *q_u,
+ prs_struct *rdata,
+ int status)
+{
+ WKS_R_QUERY_INFO r_u;
+ WKS_INFO_100 wks100;
+
+ DEBUG(5,("wks_query_info: %d\n", __LINE__));
+
+ create_wks_info_100(&wks100);
+ make_wks_r_query_info(&r_u, q_u->switch_value, &wks100, status);
+
+ /* store the response in the SMB stream */
+ wks_io_r_query_info("", &r_u, rdata, 0);
+
+ DEBUG(5,("wks_query_info: %d\n", __LINE__));
+}
+
+/*******************************************************************
+ api_wks_query_info
+ ********************************************************************/
+static void api_wks_query_info( int uid, prs_struct *data,
+ prs_struct *rdata )
+{
+ WKS_Q_QUERY_INFO q_u;
+
+ /* grab the net share enum */
+ wks_io_q_query_info("", &q_u, data, 0);
+
+ /* construct reply. always indicate success */
+ wks_reply_query_info(&q_u, rdata, 0x0);
+}
+
+
+/*******************************************************************
+ \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, prs_struct *data)
+{
+ return api_rpcTNP(p, "api_wkssvc_rpc", api_wks_cmds, data);
+}
+
diff --git a/source/rpcclient/cmd_lsarpc.c b/source/rpcclient/cmd_lsarpc.c
new file mode 100644
index 00000000000..24edb20450c
--- /dev/null
+++ b/source/rpcclient/cmd_lsarpc.c
@@ -0,0 +1,119 @@
+/*
+ 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.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+#define DEBUG_TESTING
+
+extern struct cli_state *smb_cli;
+extern int smb_tidx;
+
+extern FILE* out_hnd;
+
+
+/****************************************************************************
+nt lsa query
+****************************************************************************/
+void cmd_lsa_query_info(struct client_info *info)
+{
+ fstring srv_name;
+
+ BOOL res = True;
+
+ fstrcpy(info->dom.level3_dom, "");
+ fstrcpy(info->dom.level3_sid, "");
+ fstrcpy(info->dom.level5_dom, "");
+ fstrcpy(info->dom.level5_sid, "");
+
+ fstrcpy(srv_name, "\\\\");
+ fstrcat(srv_name, info->myhostname);
+ strupper(srv_name);
+
+ DEBUG(4,("cmd_lsa_query_info: server:%s\n", srv_name));
+
+ DEBUG(5, ("cmd_lsa_query_info: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open LSARPC session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_LSARPC, False) : False;
+
+ /* lookup domain controller; receive a policy handle */
+ res = res ? do_lsa_open_policy(smb_cli,
+ srv_name,
+ &info->dom.lsa_info_pol) : False;
+
+ /* send client info query, level 3. receive domain name and sid */
+ res = res ? do_lsa_query_info_pol(smb_cli,
+ &info->dom.lsa_info_pol, 0x03,
+ info->dom.level3_dom,
+ info->dom.level3_sid) : False;
+
+ /* send client info query, level 5. receive domain name and sid */
+ res = res ? do_lsa_query_info_pol(smb_cli,
+ &info->dom.lsa_info_pol, 0x05,
+ info->dom.level5_dom,
+ info->dom.level5_sid) : False;
+
+ res = res ? do_lsa_close(smb_cli, &info->dom.lsa_info_pol) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ BOOL domain_something = False;
+ DEBUG(5,("cmd_lsa_query_info: query succeeded\n"));
+
+ fprintf(out_hnd, "LSA Query Info Policy\n");
+
+ if (info->dom.level3_sid[0] != 0)
+ {
+ fprintf(out_hnd, "Domain Member - Domain: %s SID: %s\n",
+ info->dom.level3_dom, info->dom.level3_sid);
+ domain_something = True;
+ }
+ if (info->dom.level5_sid[0] != 0)
+ {
+ fprintf(out_hnd, "Domain Controller - Domain: %s SID: %s\n",
+ info->dom.level5_dom, info->dom.level5_sid);
+ domain_something = True;
+ }
+ if (!domain_something)
+ {
+ fprintf(out_hnd, "%s is not a Domain Member or Controller\n",
+ info->dest_host);
+ }
+ }
+ else
+ {
+ DEBUG(5,("cmd_lsa_query_info: query succeeded\n"));
+ }
+}
+
diff --git a/source/rpcclient/cmd_netlogon.c b/source/rpcclient/cmd_netlogon.c
new file mode 100644
index 00000000000..40bb257072d
--- /dev/null
+++ b/source/rpcclient/cmd_netlogon.c
@@ -0,0 +1,108 @@
+/*
+ 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.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+#define DEBUG_TESTING
+
+extern struct cli_state *smb_cli;
+
+extern FILE* out_hnd;
+
+
+/****************************************************************************
+experimental nt login.
+****************************************************************************/
+void cmd_netlogon_login_test(struct client_info *info)
+{
+ BOOL res = True;
+
+ /* machine account passwords */
+ pstring new_mach_pwd;
+
+ /* initialisation */
+ new_mach_pwd[0] = 0;
+
+ DEBUG(5,("do_nt_login_test: %d\n", __LINE__));
+
+#if 0
+ /* check whether the user wants to change their machine password */
+ res = res ? trust_account_check(info->dest_ip, info->dest_host,
+ info->myhostname, smb_cli->domain,
+ info->mach_acct, new_mach_pwd) : False;
+#endif
+ /* open NETLOGON session. negotiate credentials */
+ res = res ? do_nt_session_open(smb_cli,
+ info->dest_host, info->myhostname,
+ info->mach_acct,
+ smb_cli->user_name, smb_cli->domain,
+ info->dom.sess_key, &info->dom.clnt_cred) : False;
+
+ /* change the machine password? */
+ if (new_mach_pwd != NULL && new_mach_pwd[0] != 0)
+ {
+ res = res ? do_nt_srv_pwset(smb_cli, info->dom.lsarpc_fnum,
+ info->dom.sess_key, &info->dom.clnt_cred, &info->dom.rtn_cred,
+ new_mach_pwd,
+ info->dest_host, info->mach_acct, info->myhostname) : False;
+ }
+
+ /* create the user-identification info */
+ make_nt_login_interactive(&info->dom.ctr,
+ info->dom.sess_key,
+ smb_cli->domain, info->myhostname,
+ getuid(), smb_cli->user_name);
+
+ /* do an NT login */
+ res = res ? do_nt_login(smb_cli, info->dom.lsarpc_fnum,
+ info->dom.sess_key, &info->dom.clnt_cred, &info->dom.rtn_cred,
+ &info->dom.ctr, info->dest_host, info->myhostname, &info->dom.user_info3) : False;
+
+ /* ok! you're logged in! do anything you like, then... */
+
+ /* do an NT logout */
+ res = res ? do_nt_logoff(smb_cli, info->dom.lsarpc_fnum,
+ info->dom.sess_key, &info->dom.clnt_cred, &info->dom.rtn_cred,
+ &info->dom.ctr, info->dest_host, info->myhostname) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_nt_login: login test succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_nt_login: login test failed\n"));
+ }
+}
+
diff --git a/source/rpcclient/cmd_samr.c b/source/rpcclient/cmd_samr.c
new file mode 100644
index 00000000000..c45c4c7c23d
--- /dev/null
+++ b/source/rpcclient/cmd_samr.c
@@ -0,0 +1,587 @@
+/*
+ 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.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+#define DEBUG_TESTING
+
+extern struct cli_state *smb_cli;
+
+extern FILE* out_hnd;
+
+
+/****************************************************************************
+experimental SAM encryted rpc test connection
+****************************************************************************/
+void cmd_sam_test(struct client_info *info)
+{
+ fstring srv_name;
+ fstring domain;
+ fstring sid;
+ BOOL res = True;
+
+ fstrcpy(sid , info->dom.level5_sid);
+ fstrcpy(domain, info->dom.level5_dom);
+
+ if (strlen(sid) == 0)
+ {
+ fprintf(out_hnd, "please use 'lsaquery' first, to ascertain the SID\n");
+ return;
+ }
+
+ fstrcpy(srv_name, "\\\\");
+ fstrcat(srv_name, info->myhostname);
+ strupper(srv_name);
+
+
+ fprintf(out_hnd, "SAM Encryption Test\n");
+
+ /* open SAMR session. */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_SAMR, True) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_sam_test: succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_sam_test: failed\n"));
+ }
+}
+
+
+/****************************************************************************
+experimental SAM users enum.
+****************************************************************************/
+void cmd_sam_enum_users(struct client_info *info)
+{
+ fstring srv_name;
+ fstring domain;
+ fstring sid;
+ DOM_SID sid1;
+ int user_idx;
+ BOOL res = True;
+ BOOL request_user_info = False;
+ BOOL request_group_info = False;
+ uint16 num_entries = 0;
+ uint16 unk_0 = 0x0;
+ uint16 acb_mask = 0;
+ uint16 unk_1 = 0x0;
+ uint32 admin_rid = 0x304; /* absolutely no idea. */
+ fstring tmp;
+
+ fstrcpy(sid , info->dom.level5_sid);
+ fstrcpy(domain, info->dom.level5_dom);
+
+ if (strlen(sid) == 0)
+ {
+ fprintf(out_hnd, "please use 'lsaquery' first, to ascertain the SID\n");
+ return;
+ }
+
+ make_dom_sid(&sid1, sid);
+
+ fstrcpy(srv_name, "\\\\");
+ fstrcat(srv_name, info->dest_host);
+ strupper(srv_name);
+
+ /* a bad way to do token parsing... */
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ request_user_info |= strequal(tmp, "-u");
+ request_group_info |= strequal(tmp, "-g");
+ }
+
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ request_user_info |= strequal(tmp, "-u");
+ request_group_info |= strequal(tmp, "-g");
+ }
+
+#ifdef DEBUG_TESTING
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ num_entries = (uint16)strtoul(tmp, (char**)NULL, 16);
+ }
+
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ unk_0 = (uint16)strtoul(tmp, (char**)NULL, 16);
+ }
+
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ acb_mask = (uint16)strtoul(tmp, (char**)NULL, 16);
+ }
+
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ unk_1 = (uint16)strtoul(tmp, (char**)NULL, 16);
+ }
+#endif
+
+ fprintf(out_hnd, "SAM Enumerate Users\n");
+ fprintf(out_hnd, "From: %s To: %s Domain: %s SID: %s\n",
+ info->myhostname, srv_name, domain, sid);
+
+#ifdef DEBUG_TESTING
+ DEBUG(5,("Number of entries:%d unk_0:%04x acb_mask:%04x unk_1:%04x\n",
+ num_entries, unk_0, acb_mask, unk_1));
+#endif
+
+ /* open SAMR session. negotiate credentials */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_SAMR, False) : False;
+
+ /* establish a connection. */
+ res = res ? do_samr_connect(smb_cli,
+ srv_name, 0x00000020,
+ &info->dom.samr_pol_connect) : False;
+
+ /* connect to the domain */
+ res = res ? do_samr_open_domain(smb_cli,
+ &info->dom.samr_pol_connect, admin_rid, &sid1,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* read some users */
+ res = res ? do_samr_enum_dom_users(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ num_entries, unk_0, acb_mask, unk_1, 0xffff,
+ &info->dom.sam, &info->dom.num_sam_entries) : False;
+
+ if (res && info->dom.num_sam_entries == 0)
+ {
+ fprintf(out_hnd, "No users\n");
+ }
+
+ if (request_user_info || request_group_info)
+ {
+ /* query all the users */
+ user_idx = 0;
+
+ while (res && user_idx < info->dom.num_sam_entries)
+ {
+ uint32 user_rid = info->dom.sam[user_idx].smb_userid;
+ SAM_USER_INFO_21 usr;
+
+ fprintf(out_hnd, "User RID: %8x User Name: %s\n",
+ user_rid,
+ info->dom.sam[user_idx].acct_name);
+
+ if (request_user_info)
+ {
+ /* send user info query, level 0x15 */
+ if (get_samr_query_userinfo(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ 0x15, user_rid, &usr))
+ {
+ display_sam_user_info_21(out_hnd, ACTION_HEADER , &usr);
+ display_sam_user_info_21(out_hnd, ACTION_ENUMERATE, &usr);
+ display_sam_user_info_21(out_hnd, ACTION_FOOTER , &usr);
+ }
+ }
+
+ if (request_group_info)
+ {
+ uint32 num_groups;
+ DOM_GID gid[LSA_MAX_GROUPS];
+
+ /* send user group query */
+ if (get_samr_query_usergroups(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ user_rid, &num_groups, gid))
+ {
+ display_group_rid_info(out_hnd, ACTION_HEADER , num_groups, gid);
+ display_group_rid_info(out_hnd, ACTION_ENUMERATE, num_groups, gid);
+ display_group_rid_info(out_hnd, ACTION_FOOTER , num_groups, gid);
+ }
+ }
+
+ user_idx++;
+ }
+ }
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_connect) : False;
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (info->dom.sam != NULL)
+ {
+ free(info->dom.sam);
+ }
+
+ if (res)
+ {
+ DEBUG(5,("cmd_sam_enum_users: succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_sam_enum_users: failed\n"));
+ }
+}
+
+
+/****************************************************************************
+experimental SAM user query.
+****************************************************************************/
+void cmd_sam_query_user(struct client_info *info)
+{
+ fstring srv_name;
+ fstring domain;
+ fstring sid;
+ DOM_SID sid1;
+ int user_idx = 0; /* FIXME maybe ... */
+ BOOL res = True;
+ uint32 admin_rid = 0x304; /* absolutely no idea. */
+ fstring rid_str ;
+ fstring info_str;
+ uint32 user_rid = 0;
+ uint32 info_level = 0x15;
+
+ SAM_USER_INFO_21 usr;
+
+ fstrcpy(sid , info->dom.level5_sid);
+ fstrcpy(domain, info->dom.level5_dom);
+
+ if (strlen(sid) == 0)
+ {
+ fprintf(out_hnd, "please use 'lsaquery' first, to ascertain the SID\n");
+ return;
+ }
+
+ make_dom_sid(&sid1, sid);
+
+ fstrcpy(srv_name, "\\\\");
+ fstrcat(srv_name, info->dest_host);
+ strupper(srv_name);
+
+ if (next_token(NULL, rid_str , NULL, sizeof(rid_str )) &&
+ next_token(NULL, info_str, NULL, sizeof(info_str)))
+ {
+ user_rid = strtoul(rid_str , (char**)NULL, 16);
+ info_level = strtoul(info_str, (char**)NULL, 10);
+ }
+
+ fprintf(out_hnd, "SAM Query User: rid %x info level %d\n",
+ user_rid, info_level);
+ fprintf(out_hnd, "From: %s To: %s Domain: %s SID: %s\n",
+ info->myhostname, srv_name, domain, sid);
+
+ /* open SAMR session. negotiate credentials */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_SAMR, False) : False;
+
+ /* establish a connection. */
+ res = res ? do_samr_connect(smb_cli,
+ srv_name, 0x00000020,
+ &info->dom.samr_pol_connect) : False;
+
+ /* connect to the domain */
+ res = res ? do_samr_open_domain(smb_cli,
+ &info->dom.samr_pol_connect, admin_rid, &sid1,
+ &info->dom.samr_pol_open_domain) : False;
+
+ fprintf(out_hnd, "User RID: %8x User Name: %s\n",
+ user_rid,
+ info->dom.sam[user_idx].acct_name);
+
+ /* send user info query, level */
+ if (get_samr_query_userinfo(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ info_level, user_rid, &usr))
+ {
+ if (info_level == 0x15)
+ {
+ display_sam_user_info_21(out_hnd, ACTION_HEADER , &usr);
+ display_sam_user_info_21(out_hnd, ACTION_ENUMERATE, &usr);
+ display_sam_user_info_21(out_hnd, ACTION_FOOTER , &usr);
+ }
+ }
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_connect) : False;
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_sam_query_user: succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_sam_query_user: failed\n"));
+ }
+}
+
+
+/****************************************************************************
+experimental SAM groups query.
+****************************************************************************/
+void cmd_sam_query_groups(struct client_info *info)
+{
+ fstring srv_name;
+ fstring domain;
+ fstring sid;
+ DOM_SID sid1;
+ BOOL res = True;
+ fstring info_str;
+ uint32 switch_value = 2;
+ uint32 admin_rid = 0x304; /* absolutely no idea. */
+
+ fstrcpy(sid , info->dom.level5_sid);
+ fstrcpy(domain, info->dom.level5_dom);
+
+ if (strlen(sid) == 0)
+ {
+ fprintf(out_hnd, "please use 'lsaquery' first, to ascertain the SID\n");
+ return;
+ }
+
+ make_dom_sid(&sid1, sid);
+
+ fstrcpy(srv_name, "\\\\");
+ fstrcat(srv_name, info->dest_host);
+ strupper(srv_name);
+
+ if (next_token(NULL, info_str, NULL, sizeof(info_str)))
+ {
+ switch_value = strtoul(info_str, (char**)NULL, 10);
+ }
+
+ fprintf(out_hnd, "SAM Query Groups: info level %d\n", switch_value);
+ fprintf(out_hnd, "From: %s To: %s Domain: %s SID: %s\n",
+ info->myhostname, srv_name, domain, sid);
+
+ /* open SAMR session. negotiate credentials */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_SAMR, False) : False;
+
+ /* establish a connection. */
+ res = res ? do_samr_connect(smb_cli,
+ srv_name, 0x00000020,
+ &info->dom.samr_pol_connect) : False;
+
+ /* connect to the domain */
+ res = res ? do_samr_open_domain(smb_cli,
+ &info->dom.samr_pol_connect, admin_rid, &sid1,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* send a samr 0x8 command */
+ res = res ? do_samr_unknown_8(smb_cli,
+ &info->dom.samr_pol_open_domain, switch_value) : False;
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_connect) : False;
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_sam_query_groups: succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_sam_query_groups: failed\n"));
+ }
+}
+
+
+/****************************************************************************
+experimental SAM aliases query.
+****************************************************************************/
+void cmd_sam_enum_aliases(struct client_info *info)
+{
+ fstring srv_name;
+ fstring domain;
+ fstring sid;
+ DOM_SID sid1;
+ BOOL res = True;
+ BOOL request_user_info = False;
+ BOOL request_alias_info = False;
+ uint32 admin_rid = 0x304; /* absolutely no idea. */
+ fstring tmp;
+
+ uint32 num_aliases = 3;
+ uint32 alias_rid[3] = { DOMAIN_GROUP_RID_ADMINS, DOMAIN_GROUP_RID_USERS, DOMAIN_GROUP_RID_GUESTS };
+ fstring alias_names [3];
+ uint32 num_als_usrs[3];
+
+ fstrcpy(sid , info->dom.level5_sid);
+ fstrcpy(domain, info->dom.level5_dom);
+
+ if (strlen(sid) == 0)
+ {
+ fprintf(out_hnd, "please use 'lsaquery' first, to ascertain the SID\n");
+ return;
+ }
+
+ make_dom_sid(&sid1, sid);
+
+ fstrcpy(srv_name, "\\\\");
+ fstrcat(srv_name, info->dest_host);
+ strupper(srv_name);
+
+ /* a bad way to do token parsing... */
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ request_user_info |= strequal(tmp, "-u");
+ request_alias_info |= strequal(tmp, "-g");
+ }
+
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ request_user_info |= strequal(tmp, "-u");
+ request_alias_info |= strequal(tmp, "-g");
+ }
+
+ fprintf(out_hnd, "SAM Enumerate Aliases\n");
+ fprintf(out_hnd, "From: %s To: %s Domain: %s SID: %s\n",
+ info->myhostname, srv_name, domain, sid);
+
+ /* open SAMR session. negotiate credentials */
+ res = res ? cli_nt_session_open(smb_cli, PIPE_SAMR, False) : False;
+
+ /* establish a connection. */
+ res = res ? do_samr_connect(smb_cli,
+ srv_name, 0x00000020,
+ &info->dom.samr_pol_connect) : False;
+
+ /* connect to the domain */
+ res = res ? do_samr_open_domain(smb_cli,
+ &info->dom.samr_pol_connect, admin_rid, &sid1,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* send a query on the aliase */
+ res = res ? do_samr_query_unknown_12(smb_cli,
+ &info->dom.samr_pol_open_domain, admin_rid, num_aliases, alias_rid,
+ &num_aliases, alias_names, num_als_usrs) : False;
+
+ if (res)
+ {
+ display_alias_name_info(out_hnd, ACTION_HEADER , num_aliases, alias_names, num_als_usrs);
+ display_alias_name_info(out_hnd, ACTION_ENUMERATE, num_aliases, alias_names, num_als_usrs);
+ display_alias_name_info(out_hnd, ACTION_FOOTER , num_aliases, alias_names, num_als_usrs);
+ }
+
+#if 0
+
+ /* read some users */
+ res = res ? do_samr_enum_dom_users(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ num_entries, unk_0, acb_mask, unk_1, 0xffff,
+ info->dom.sam, &info->dom.num_sam_entries) : False;
+
+ if (res && info->dom.num_sam_entries == 0)
+ {
+ fprintf(out_hnd, "No users\n");
+ }
+
+ if (request_user_info || request_alias_info)
+ {
+ /* query all the users */
+ user_idx = 0;
+
+ while (res && user_idx < info->dom.num_sam_entries)
+ {
+ uint32 user_rid = info->dom.sam[user_idx].smb_userid;
+ SAM_USER_INFO_21 usr;
+
+ fprintf(out_hnd, "User RID: %8x User Name: %s\n",
+ user_rid,
+ info->dom.sam[user_idx].acct_name);
+
+ if (request_user_info)
+ {
+ /* send user info query, level 0x15 */
+ if (get_samr_query_userinfo(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ 0x15, user_rid, &usr))
+ {
+ display_sam_user_info_21(out_hnd, ACTION_HEADER , &usr);
+ display_sam_user_info_21(out_hnd, ACTION_ENUMERATE, &usr);
+ display_sam_user_info_21(out_hnd, ACTION_FOOTER , &usr);
+ }
+ }
+
+ if (request_alias_info)
+ {
+ uint32 num_aliases;
+ DOM_GID gid[LSA_MAX_GROUPS];
+
+ /* send user aliase query */
+ if (get_samr_query_useraliases(smb_cli,
+ &info->dom.samr_pol_open_domain,
+ user_rid, &num_aliases, gid))
+ {
+ display_alias_info(out_hnd, ACTION_HEADER , num_aliases, gid);
+ display_alias_info(out_hnd, ACTION_ENUMERATE, num_aliases, gid);
+ display_alias_info(out_hnd, ACTION_FOOTER , num_aliases, gid);
+ }
+ }
+
+ user_idx++;
+ }
+ }
+#endif
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_connect) : False;
+
+ res = res ? do_samr_close(smb_cli,
+ &info->dom.samr_pol_open_domain) : False;
+
+ /* close the session */
+ cli_nt_session_close(smb_cli);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_sam_enum_users: succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_sam_enum_users: failed\n"));
+ }
+}
+
+
diff --git a/source/rpcclient/cmd_srvsvc.c b/source/rpcclient/cmd_srvsvc.c
new file mode 100644
index 00000000000..2964d1b54b0
--- /dev/null
+++ b/source/rpcclient/cmd_srvsvc.c
@@ -0,0 +1,329 @@
+/*
+ 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.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+#define DEBUG_TESTING
+
+extern struct cli_state *smb_cli;
+extern int smb_tidx;
+
+extern FILE* out_hnd;
+
+
+/****************************************************************************
+server get info query
+****************************************************************************/
+void cmd_srv_query_info(struct client_info *info)
+{
+ fstring dest_srv;
+ fstring tmp;
+ SRV_INFO_CTR ctr;
+ uint32 info_level = 101;
+
+ BOOL res = True;
+
+ bzero(&ctr, sizeof(ctr));
+
+ strcpy(dest_srv, "\\\\");
+ strcat(dest_srv, info->dest_host);
+ strupper(dest_srv);
+
+ if (next_token(NULL, tmp, NULL))
+ {
+ info_level = strtoul(tmp, (char**)NULL, 10);
+ }
+
+ DEBUG(4,("cmd_srv_query_info: server:%s info level: %D\n",
+ dest_srv, info_level));
+
+ DEBUG(5, ("cmd_srv_query_info: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open LSARPC session. */
+ res = res ? do_session_open(smb_cli, smb_tidx, PIPE_SRVSVC, &(info->dom.srvsvc_fnum)) : False;
+
+ /* send info level: receive requested info. hopefully. */
+ res = res ? do_srv_net_srv_get_info(smb_cli, smb_tidx, info->dom.srvsvc_fnum,
+ dest_srv, info_level, &ctr) : False;
+
+ /* close the session */
+ do_session_close(smb_cli, smb_tidx, info->dom.srvsvc_fnum);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_srv_query_info: query succeeded\n"));
+
+ display_srv_info_ctr(out_hnd, ACTION_HEADER , &ctr);
+ display_srv_info_ctr(out_hnd, ACTION_ENUMERATE, &ctr);
+ display_srv_info_ctr(out_hnd, ACTION_FOOTER , &ctr);
+ }
+ else
+ {
+ DEBUG(5,("cmd_srv_query_info: query failed\n"));
+ }
+}
+
+/****************************************************************************
+server enum connections
+****************************************************************************/
+void cmd_srv_enum_conn(struct client_info *info)
+{
+ fstring dest_srv;
+ fstring qual_srv;
+ fstring tmp;
+ SRV_CONN_INFO_CTR ctr;
+ ENUM_HND hnd;
+ uint32 info_level = 0;
+
+ BOOL res = True;
+
+ bzero(&ctr, sizeof(ctr));
+
+ strcpy(qual_srv, "\\\\");
+ strcat(qual_srv, info->myhostname);
+ strupper(qual_srv);
+
+ strcpy(dest_srv, "\\\\");
+ strcat(dest_srv, info->dest_host);
+ strupper(dest_srv);
+
+ if (next_token(NULL, tmp, NULL))
+ {
+ info_level = strtoul(tmp, (char**)NULL, 10);
+ }
+
+ DEBUG(4,("cmd_srv_enum_conn: server:%s info level: %D\n",
+ dest_srv, info_level));
+
+ DEBUG(5, ("cmd_srv_enum_conn: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open srvsvc session. */
+ res = res ? do_session_open(smb_cli, smb_tidx, PIPE_SRVSVC, &(info->dom.srvsvc_fnum)) : False;
+
+ hnd.ptr_hnd = 1;
+ hnd.handle = 0;
+
+ /* enumerate connections on server */
+ res = res ? do_srv_net_srv_conn_enum(smb_cli, smb_tidx, info->dom.srvsvc_fnum,
+ dest_srv, qual_srv,
+ info_level, &ctr, 0xffffffff, &hnd) : False;
+
+ if (res)
+ {
+ display_srv_conn_info_ctr(out_hnd, ACTION_HEADER , &ctr);
+ display_srv_conn_info_ctr(out_hnd, ACTION_ENUMERATE, &ctr);
+ display_srv_conn_info_ctr(out_hnd, ACTION_FOOTER , &ctr);
+ }
+
+ /* close the session */
+ do_session_close(smb_cli, smb_tidx, info->dom.srvsvc_fnum);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_srv_enum_conn: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_srv_enum_conn: query failed\n"));
+ }
+}
+
+/****************************************************************************
+server enum shares
+****************************************************************************/
+void cmd_srv_enum_shares(struct client_info *info)
+{
+ fstring dest_srv;
+ fstring tmp;
+ SRV_SHARE_INFO_CTR ctr;
+ ENUM_HND hnd;
+ uint32 info_level = 1;
+
+ BOOL res = True;
+
+ bzero(&ctr, sizeof(ctr));
+
+ strcpy(dest_srv, "\\\\");
+ strcat(dest_srv, info->dest_host);
+ strupper(dest_srv);
+
+ if (next_token(NULL, tmp, NULL))
+ {
+ info_level = strtoul(tmp, (char**)NULL, 10);
+ }
+
+ DEBUG(4,("cmd_srv_enum_shares: server:%s info level: %D\n",
+ dest_srv, info_level));
+
+ DEBUG(5, ("cmd_srv_enum_shares: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open srvsvc session. */
+ res = res ? do_session_open(smb_cli, smb_tidx, PIPE_SRVSVC, &(info->dom.srvsvc_fnum)) : False;
+
+ hnd.ptr_hnd = 0;
+ hnd.handle = 0;
+
+ /* enumerate shares_files on server */
+ res = res ? do_srv_net_srv_share_enum(smb_cli, smb_tidx, info->dom.srvsvc_fnum,
+ dest_srv,
+ info_level, &ctr, 0xffffffff, &hnd) : False;
+
+ if (res)
+ {
+ display_srv_share_info_ctr(out_hnd, ACTION_HEADER , &ctr);
+ display_srv_share_info_ctr(out_hnd, ACTION_ENUMERATE, &ctr);
+ display_srv_share_info_ctr(out_hnd, ACTION_FOOTER , &ctr);
+ }
+
+ /* close the session */
+ do_session_close(smb_cli, smb_tidx, info->dom.srvsvc_fnum);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_srv_enum_shares: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_srv_enum_shares: query failed\n"));
+ }
+}
+
+/****************************************************************************
+server enum sessions
+****************************************************************************/
+void cmd_srv_enum_sess(struct client_info *info)
+{
+ fstring dest_srv;
+ fstring tmp;
+ SRV_SESS_INFO_CTR ctr;
+ ENUM_HND hnd;
+ uint32 info_level = 0;
+
+ BOOL res = True;
+
+ bzero(&ctr, sizeof(ctr));
+
+ strcpy(dest_srv, "\\\\");
+ strcat(dest_srv, info->dest_host);
+ strupper(dest_srv);
+
+ if (next_token(NULL, tmp, NULL))
+ {
+ info_level = strtoul(tmp, (char**)NULL, 10);
+ }
+
+ DEBUG(4,("cmd_srv_enum_sess: server:%s info level: %D\n",
+ dest_srv, info_level));
+
+ DEBUG(5, ("cmd_srv_enum_sess: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open srvsvc session. */
+ res = res ? do_session_open(smb_cli, smb_tidx, PIPE_SRVSVC, &(info->dom.srvsvc_fnum)) : False;
+
+ hnd.ptr_hnd = 1;
+ hnd.handle = 0;
+
+ /* enumerate sessions on server */
+ res = res ? do_srv_net_srv_sess_enum(smb_cli, smb_tidx, info->dom.srvsvc_fnum,
+ dest_srv, NULL, info_level, &ctr, 0x1000, &hnd) : False;
+
+ /* close the session */
+ do_session_close(smb_cli, smb_tidx, info->dom.srvsvc_fnum);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_srv_enum_sess: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_srv_enum_sess: query failed\n"));
+ }
+}
+
+/****************************************************************************
+server enum files
+****************************************************************************/
+void cmd_srv_enum_files(struct client_info *info)
+{
+ fstring dest_srv;
+ fstring tmp;
+ SRV_FILE_INFO_CTR ctr;
+ ENUM_HND hnd;
+ uint32 info_level = 3;
+
+ BOOL res = True;
+
+ bzero(&ctr, sizeof(ctr));
+
+ strcpy(dest_srv, "\\\\");
+ strcat(dest_srv, info->dest_host);
+ strupper(dest_srv);
+
+ if (next_token(NULL, tmp, NULL))
+ {
+ info_level = strtoul(tmp, (char**)NULL, 10);
+ }
+
+ DEBUG(4,("cmd_srv_enum_files: server:%s info level: %D\n",
+ dest_srv, info_level));
+
+ DEBUG(5, ("cmd_srv_enum_files: smb_cli->fd:%d\n", smb_cli->fd));
+
+ /* open srvsvc session. */
+ res = res ? do_session_open(smb_cli, smb_tidx, PIPE_SRVSVC, &(info->dom.srvsvc_fnum)) : False;
+
+ hnd.ptr_hnd = 1;
+ hnd.handle = 0;
+
+ /* enumerate files on server */
+ res = res ? do_srv_net_srv_file_enum(smb_cli, smb_tidx, info->dom.srvsvc_fnum,
+ dest_srv, NULL, info_level, &ctr, 0x1000, &hnd) : False;
+
+ if (res)
+ {
+ display_srv_file_info_ctr(out_hnd, ACTION_HEADER , &ctr);
+ display_srv_file_info_ctr(out_hnd, ACTION_ENUMERATE, &ctr);
+ display_srv_file_info_ctr(out_hnd, ACTION_FOOTER , &ctr);
+ }
+
+ /* close the session */
+ do_session_close(smb_cli, smb_tidx, info->dom.srvsvc_fnum);
+
+ if (res)
+ {
+ DEBUG(5,("cmd_srv_enum_files: query succeeded\n"));
+ }
+ else
+ {
+ DEBUG(5,("cmd_srv_enum_files: query failed\n"));
+ }
+}
+
diff --git a/source/rpcclient/cmd_wkssvc.c b/source/rpcclient/cmd_wkssvc.c
new file mode 100644
index 00000000000..350aa296577
--- /dev/null
+++ b/source/rpcclient/cmd_wkssvc.c
@@ -0,0 +1,95 @@
+/*
+ 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.
+*/
+
+
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+
+#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;
+
+ bzero(&ctr, sizeof(ctr));
+
+ fstrcpy(dest_wks, "\\\\");
+ fstrcat(dest_wks, info->dest_host);
+ strupper(dest_wks);
+
+ if (next_token(NULL, tmp, NULL, sizeof(tmp)))
+ {
+ info_level = strtoul(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) : 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..f399b7fc031
--- /dev/null
+++ b/source/rpcclient/display.c
@@ -0,0 +1,1013 @@
+/*
+ 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 ((share_mode>>4)&0xF)
+ {
+ 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;
+ 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 = IS_BITS_SET_ALL(op_type, EXCLUSIVE_OPLOCK);
+ BOOL batch = IS_BITS_SET_ALL(op_type, BATCH_OPLOCK );
+
+ 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 (IS_BITS_SET_ALL(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;
+}
+
+/****************************************************************************
+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;
+
+ fstrcpy(name , unistrn2(sv101->uni_name .buffer, sv101->uni_name .uni_str_len));
+ fstrcpy(comment , unistrn2(sv101->uni_comment .buffer, sv101->uni_comment .uni_str_len));
+
+ 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;
+
+ fstrcpy(name , unistrn2(sv102->uni_name .buffer, sv102->uni_name .uni_str_len));
+ fstrcpy(comment , unistrn2(sv102->uni_comment .buffer, sv102->uni_comment .uni_str_len));
+ fstrcpy(usr_path, unistrn2(sv102->uni_usr_path.buffer, sv102->uni_usr_path.uni_str_len));
+
+ 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;
+
+ fstrcpy(usr_name, unistrn2(str1->uni_usr_name.buffer, str1->uni_usr_name.uni_str_len));
+ fstrcpy(net_name, unistrn2(str1->uni_net_name.buffer, str1->uni_net_name.uni_str_len));
+
+ 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,
+ SH_INFO_1 *info1, SH_INFO_1_STR *str1)
+{
+ if (info1 == NULL || str1 == NULL)
+ {
+ return;
+ }
+
+ switch (action)
+ {
+ case ACTION_HEADER:
+ {
+ fprintf(out_hnd, "Share Info Level 1:\n");
+
+ break;
+ }
+ case ACTION_ENUMERATE:
+ {
+ fstring remark ;
+ fstring net_name;
+
+ fstrcpy(net_name, unistrn2(str1->uni_netname.buffer, str1->uni_netname.uni_str_len));
+ fstrcpy(remark , unistrn2(str1->uni_remark .buffer, str1->uni_remark .uni_str_len));
+
+ display_share(out_hnd, action, net_name, info1->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,
+ SH_INFO_2 *info2, SH_INFO_2_STR *str2)
+{
+ if (info2 == NULL || str2 == 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 ;
+
+ fstrcpy(net_name, unistrn2(str2->uni_netname.buffer, str2->uni_netname.uni_str_len));
+ fstrcpy(remark , unistrn2(str2->uni_remark .buffer, str2->uni_remark .uni_str_len));
+ fstrcpy(path , unistrn2(str2->uni_path .buffer, str2->uni_path .uni_str_len));
+ fstrcpy(passwd , unistrn2(str2->uni_passwd .buffer, str2->uni_passwd .uni_str_len));
+
+ display_share2(out_hnd, action, net_name, info2->type, remark,
+ info2->perms, info2->max_uses, info2->num_uses,
+ path, passwd);
+
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ fprintf(out_hnd, "\n");
+ break;
+ }
+ }
+
+}
+
+/****************************************************************************
+share info level 1 container display function
+****************************************************************************/
+void display_srv_share_info_1_ctr(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_1 *ctr)
+{
+ if (ctr == NULL)
+ {
+ fprintf(out_hnd, "display_srv_share_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_share_info_1(out_hnd, ACTION_HEADER , &(ctr->info_1[i]), &(ctr->info_1_str[i]));
+ display_share_info_1(out_hnd, ACTION_ENUMERATE, &(ctr->info_1[i]), &(ctr->info_1_str[i]));
+ display_share_info_1(out_hnd, ACTION_FOOTER , &(ctr->info_1[i]), &(ctr->info_1_str[i]));
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+share info level 2 container display function
+****************************************************************************/
+void display_srv_share_info_2_ctr(FILE *out_hnd, enum action_type action,
+ SRV_SHARE_INFO_2 *ctr)
+{
+ if (ctr == NULL)
+ {
+ fprintf(out_hnd, "display_srv_share_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 < ctr->num_entries_read; i++)
+ {
+ display_share_info_2(out_hnd, ACTION_HEADER , &(ctr->info_2[i]), &(ctr->info_2_str[i]));
+ display_share_info_2(out_hnd, ACTION_ENUMERATE, &(ctr->info_2[i]), &(ctr->info_2_str[i]));
+ display_share_info_2(out_hnd, ACTION_FOOTER , &(ctr->info_2[i]), &(ctr->info_2_str[i]));
+ }
+ break;
+ }
+ case ACTION_FOOTER:
+ {
+ 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 || ctr->ptr_share_ctr == 0)
+ {
+ fprintf(out_hnd, "display_srv_share_info_ctr: unavailable due to an internal error\n");
+ return;
+ }
+
+ switch (ctr->switch_value)
+ {
+ case 1:
+ {
+ display_srv_share_info_1_ctr(out_hnd, action,
+ &(ctr->share.info1));
+ break;
+ }
+ case 2:
+ {
+ display_srv_share_info_2_ctr(out_hnd, action,
+ &(ctr->share.info2));
+ break;
+ }
+ default:
+ {
+ fprintf(out_hnd, "display_srv_share_info_ctr: Unknown Info Level\n");
+ 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;
+
+ fstrcpy(path_name, unistrn2(str3->uni_path_name.buffer, str3->uni_path_name.uni_str_len));
+ fstrcpy(user_name, unistrn2(str3->uni_user_name.buffer, str3->uni_user_name.uni_str_len));
+
+ 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:
+ {
+ fprintf(out_hnd, "\t\tUser Name : %s\n", unistrn2(usr->uni_user_name .buffer, usr->uni_user_name .uni_str_len)); /* username unicode string */
+ fprintf(out_hnd, "\t\tFull Name : %s\n", unistrn2(usr->uni_full_name .buffer, usr->uni_full_name .uni_str_len)); /* user's full name unicode string */
+ fprintf(out_hnd, "\t\tHome Drive : %s\n", unistrn2(usr->uni_home_dir .buffer, usr->uni_home_dir .uni_str_len)); /* home directory unicode string */
+ fprintf(out_hnd, "\t\tDir Drive : %s\n", unistrn2(usr->uni_dir_drive .buffer, usr->uni_dir_drive .uni_str_len)); /* home directory drive unicode string */
+ fprintf(out_hnd, "\t\tProfile Path: %s\n", unistrn2(usr->uni_profile_path.buffer, usr->uni_profile_path.uni_str_len)); /* profile path unicode string */
+ fprintf(out_hnd, "\t\tLogon Script: %s\n", unistrn2(usr->uni_logon_script.buffer, usr->uni_logon_script.uni_str_len)); /* logon script unicode string */
+ fprintf(out_hnd, "\t\tDescription : %s\n", unistrn2(usr->uni_acct_desc .buffer, usr->uni_acct_desc .uni_str_len)); /* user description unicode string */
+ fprintf(out_hnd, "\t\tWorkstations: %s\n", unistrn2(usr->uni_workstations.buffer, usr->uni_workstations.uni_str_len)); /* workstaions unicode string */
+ fprintf(out_hnd, "\t\tUnknown Str : %s\n", unistrn2(usr->uni_unknown_str .buffer, usr->uni_unknown_str .uni_str_len)); /* unknown string unicode string */
+ fprintf(out_hnd, "\t\tRemote Dial : %s\n", unistrn2(usr->uni_munged_dial .buffer, usr->uni_munged_dial .uni_str_len)); /* munged remote access unicode string */
+
+ fprintf(out_hnd, "\t\tLogon Time : %s\n", http_timestring(interpret_nt_time(&(usr->logon_time ))));
+ fprintf(out_hnd, "\t\tLogoff Time : %s\n", http_timestring(interpret_nt_time(&(usr->logoff_time ))));
+ fprintf(out_hnd, "\t\tKickoff Time : %s\n", http_timestring(interpret_nt_time(&(usr->kickoff_time ))));
+ fprintf(out_hnd, "\t\tPassword last set Time : %s\n", http_timestring(interpret_nt_time(&(usr->pass_last_set_time ))));
+ fprintf(out_hnd, "\t\tPassword can change Time : %s\n", http_timestring(interpret_nt_time(&(usr->pass_can_change_time ))));
+ fprintf(out_hnd, "\t\tPassword must change Time: %s\n", http_timestring(interpret_nt_time(&(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;
+ }
+ }
+}
+
diff --git a/source/rpcclient/rpcclient.c b/source/rpcclient/rpcclient.c
new file mode 100644
index 00000000000..29211441083
--- /dev/null
+++ b/source/rpcclient/rpcclient.c
@@ -0,0 +1,756 @@
+/*
+ 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.
+*/
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+
+#ifndef REGISTER
+#define REGISTER 0
+#endif
+
+extern pstring scope;
+
+extern pstring user_socket_options;
+
+
+extern pstring debugf;
+extern int DEBUGLEVEL;
+
+
+extern file_info def_finfo;
+
+#define CNV_LANG(s) dos2unix_format(s,False)
+#define CNV_INPUT(s) unix2dos_format(s,True)
+
+static int process_tok(fstring tok);
+static void cmd_help(struct client_info *info);
+static void cmd_quit(struct client_info *info);
+
+static struct cli_state smbcli;
+struct cli_state *smb_cli = &smbcli;
+
+FILE *out_hnd = stdout;
+
+/****************************************************************************
+initialise smb client structure
+****************************************************************************/
+void rpcclient_init(void)
+{
+ bzero(smb_cli, sizeof(smb_cli));
+ cli_initialise(smb_cli);
+}
+
+/****************************************************************************
+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, scope);
+ make_nmb_name(&calling, dns_to_netbios_name(info->myhostname), 0x0 , scope);
+
+ 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);
+}
+/****************************************************************************
+ This defines the commands supported by this client
+ ****************************************************************************/
+struct
+{
+ char *name;
+ void (*fn)(struct client_info*);
+ char *description;
+} commands[] =
+{
+#if 0
+ {"ntlogin", cmd_netlogon_login_test, "<username> NT Domain login test"},
+#endif
+ {"wksinfo", cmd_wks_query_info, "DCE/RPC - Workstation Query Info"},
+#if 0
+ {"srvinfo", cmd_srv_query_info, "DCE/RPC - Server Query Info"},
+ {"srvsessions",cmd_srv_enum_sess, "DCE/RPC - List sessions on a server"},
+ {"srvshares", cmd_srv_enum_shares, "DCE/RPC - List shares on a server"},
+ {"srvconnections",cmd_srv_enum_conn, "DCE/RPC - List connections on a server"},
+ {"srvfiles", cmd_srv_enum_files, "DCE/RPC - List files on a server"},
+#endif
+ {"lsaquery", cmd_lsa_query_info, "Query Info Policy (domain member or server)"},
+ {"enumusers", cmd_sam_enum_users, "SAM User Database Query (experimental!)"},
+ {"samuser", cmd_sam_query_user, "<username> SAM User Query (experimental!)"},
+ {"samtest", cmd_sam_test , "SAM User Encrypted RPC test (experimental!)"},
+ {"enumaliases",cmd_sam_enum_aliases, "SAM Aliases Database Query (experimental!)"},
+#if 0
+ {"enumgroups", cmd_sam_enum_groups, "SAM Group Database Query (experimental!)"},
+#endif
+ {"samgroups", cmd_sam_query_groups, "SAM Group Database Query (experimental!)"},
+ {"quit", cmd_quit, "logoff the server"},
+ {"q", cmd_quit, "logoff the server"},
+ {"exit", cmd_quit, "logoff the server"},
+ {"bye", cmd_quit, "logoff the server"},
+ {"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}
+};
+
+
+/****************************************************************************
+do a (presumably graceful) quit...
+****************************************************************************/
+static void cmd_quit(struct client_info *info)
+{
+ rpcclient_stop();
+#ifdef MEM_MAN
+ {
+ extern FILE* dbf;
+ smb_mem_write_status(dbf);
+ smb_mem_write_errors(dbf);
+ smb_mem_write_verbose(dbf);
+ }
+#endif
+ exit(0);
+}
+
+/****************************************************************************
+help
+****************************************************************************/
+static void cmd_help(struct client_info *info)
+{
+ int i=0,j;
+ fstring buf;
+
+ if (next_token(NULL,buf,NULL, sizeof(buf)))
+ {
+ if ((i = process_tok(buf)) >= 0)
+ fprintf(out_hnd, "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++) {
+ fprintf(out_hnd, "%-15s",commands[i].name);
+ i++;
+ }
+ fprintf(out_hnd, "\n");
+ }
+}
+
+/*******************************************************************
+ lookup a command string in the list of commands, including
+ abbreviations
+ ******************************************************************/
+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))
+ {
+ matches++;
+ cmd = i;
+ }
+ i++;
+ }
+
+ if (matches == 0)
+ return(-1);
+ else if (matches == 1)
+ return(cmd);
+ else
+ return(-2);
+}
+
+/****************************************************************************
+wait for keyboard activity, swallowing network packets
+****************************************************************************/
+static void wait_keyboard(struct cli_state *cli)
+{
+ fd_set fds;
+ struct timeval timeout;
+
+ while (1)
+ {
+ FD_ZERO(&fds);
+ FD_SET(cli->fd,&fds);
+ FD_SET(fileno(stdin),&fds);
+
+ timeout.tv_sec = 20;
+ timeout.tv_usec = 0;
+ sys_select(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
+
+ if (FD_ISSET(fileno(stdin),&fds))
+ return;
+
+ /* 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);
+ }
+}
+
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
+static void do_command(struct client_info *info, char *tok, char *line)
+{
+ int i;
+
+ if ((i = process_tok(tok)) >= 0)
+ {
+ commands[i].fn(info);
+ }
+ else if (i == -2)
+ {
+ fprintf(out_hnd, "%s: command abbreviation ambiguous\n", CNV_LANG(tok));
+ }
+ else
+ {
+ fprintf(out_hnd, "%s: command not found\n", CNV_LANG(tok));
+ }
+}
+
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
+static BOOL process( struct client_info *info, char *cmd_str)
+{
+ pstring line;
+ char *cmd = cmd_str;
+
+ if (cmd[0] != '\0') while (cmd[0] != '\0')
+ {
+ char *p;
+ fstring tok;
+
+ if ((p = strchr(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;
+ }
+
+ /* input language code to internal one */
+ CNV_INPUT (line);
+
+ /* get the first part of the command */
+ {
+ char *ptr = line;
+ if (!next_token(&ptr,tok,NULL, sizeof(tok))) continue;
+ }
+
+ do_command(info, tok, line);
+ }
+ else while (!feof(stdin))
+ {
+ fstring tok;
+
+ /* display a prompt */
+ fprintf(out_hnd, "smb: %s> ", CNV_LANG(info->cur_dir));
+ fflush(out_hnd);
+
+#ifdef CLIX
+ line[0] = wait_keyboard(smb_cli);
+ /* this might not be such a good idea... */
+ if ( line[0] == EOF)
+ {
+ break;
+ }
+#else
+ wait_keyboard(smb_cli);
+#endif
+
+ /* and get a response */
+#ifdef CLIX
+ fgets( &line[1],999, stdin);
+#else
+ if (!fgets(line,1000,stdin))
+ {
+ break;
+ }
+#endif
+
+ /* input language code to internal one */
+ CNV_INPUT (line);
+
+ /* special case - first char is ! */
+ if (*line == '!')
+ {
+ system(line + 1);
+ continue;
+ }
+
+ fprintf(out_hnd, "%s\n", line);
+
+ /* get the first part of the command */
+ {
+ char *ptr = line;
+ if (!next_token(&ptr,tok,NULL, sizeof(tok))) continue;
+ }
+
+ do_command(info, tok, line);
+ }
+
+ return(True);
+}
+
+/****************************************************************************
+usage on the program
+****************************************************************************/
+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-N don't ask for a password\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-c command string execute semicolon separated commands\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 FILE *dbf;
+ extern char *optarg;
+ extern int optind;
+ static pstring servicesf = CONFIGFILE;
+ pstring term_code;
+ char *p;
+ BOOL got_pass = False;
+ char *cmd_str="";
+ mode_t myumask = 0755;
+ enum client_action cli_action = CLIENT_NONE;
+
+ struct client_info cli_info;
+
+ pstring password; /* local copy only, if one is entered */
+
+ rpcclient_init();
+
+#ifdef KANJI
+ pstrcpy(term_code, KANJI);
+#else /* KANJI */
+ *term_code = 0;
+#endif /* KANJI */
+
+ DEBUGLEVEL = 2;
+
+ 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, "");
+
+ pstrcpy(cli_info.dom.level3_sid, "");
+ pstrcpy(cli_info.dom.level3_dom, "");
+ pstrcpy(cli_info.dom.level5_sid, "");
+ pstrcpy(cli_info.dom.level5_dom, "");
+
+ smb_cli->nt_pipe_fnum = 0xffff;
+
+ setup_logging(pname, True);
+
+ TimeInit();
+ charset_initialise();
+
+ myumask = umask(0);
+ umask(myumask);
+
+ if (getenv("USER"))
+ {
+ pstrcpy(smb_cli->user_name,getenv("USER"));
+
+ /* modification to support userid%passwd syntax in the USER var
+ 25.Aug.97, jdblair@uab.edu */
+
+ if ((p=strchr(smb_cli->user_name,'%')))
+ {
+ *p = 0;
+ pstrcpy(password,p+1);
+ got_pass = True;
+ memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
+ }
+ strupper(smb_cli->user_name);
+ }
+
+ password[0] = 0;
+
+ /* modification to support PASSWD environmental var
+ 25.Aug.97, jdblair@uab.edu */
+ if (getenv("PASSWD"))
+ {
+ pstrcpy(password,getenv("PASSWD"));
+ }
+
+ if (*smb_cli->user_name == 0 && getenv("LOGNAME"))
+ {
+ pstrcpy(smb_cli->user_name,getenv("LOGNAME"));
+ strupper(smb_cli->user_name);
+ }
+
+ 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:B:O:M:S:i: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 'B':
+ {
+ iface_set_default(NULL,optarg,NULL);
+ break;
+ }
+
+ case 'i':
+ {
+ pstrcpy(scope, optarg);
+ break;
+ }
+
+ case 'U':
+ {
+ char *lp;
+ pstrcpy(smb_cli->user_name,optarg);
+ if ((lp=strchr(smb_cli->user_name,'%')))
+ {
+ *lp = 0;
+ pstrcpy(password,lp+1);
+ got_pass = True;
+ memset(strchr(optarg,'%')+1,'X',strlen(password));
+ }
+ break;
+ }
+
+ case 'W':
+ {
+ pstrcpy(smb_cli->domain,optarg);
+ break;
+ }
+
+ case 'E':
+ {
+ dbf = stderr;
+ break;
+ }
+
+ case 'I':
+ {
+ cli_info.dest_ip = *interpret_addr2(optarg);
+ if (zero_ip(cli_info.dest_ip))
+ {
+ exit(1);
+ }
+ break;
+ }
+
+ case 'N':
+ {
+ got_pass = True;
+ break;
+ }
+
+ case 'd':
+ {
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ }
+
+ case 'l':
+ {
+ slprintf(debugf, sizeof(debugf)-1,
+ "%s.client",optarg);
+ break;
+ }
+
+ case 'c':
+ {
+ cmd_str = optarg;
+ got_pass = True;
+ break;
+ }
+
+ case 'h':
+ {
+ usage(pname);
+ exit(0);
+ break;
+ }
+
+ case 's':
+ {
+ pstrcpy(servicesf, optarg);
+ break;
+ }
+
+ case 't':
+ {
+ pstrcpy(term_code, optarg);
+ break;
+ }
+
+ default:
+ {
+ usage(pname);
+ exit(1);
+ break;
+ }
+ }
+ }
+
+ if (cli_action == CLIENT_NONE)
+ {
+ usage(pname);
+ exit(1);
+ }
+
+ DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION));
+
+ if (!get_myname(cli_info.myhostname, NULL))
+ {
+ fprintf(stderr, "Failed to get my hostname.\n");
+ }
+
+ if (!lp_load(servicesf,True, False, False))
+ {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ }
+
+ codepage_initialise(lp_client_code_page());
+
+ if (*smb_cli->domain == 0) pstrcpy(smb_cli->domain,lp_workgroup());
+
+ 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
+ {
+ pwd_read(&(smb_cli->pwd), "Enter Password:", True);
+ }
+
+ /* paranoia: destroy the local copy of the password */
+ bzero(password, sizeof(password));
+
+ /* establish connections. nothing to stop these being re-established. */
+ rpcclient_connect(&cli_info);
+
+ DEBUG(5,("rpcclient_connect: smb_cli->fd:%d\n", smb_cli->fd));
+ if (smb_cli->fd <= 0)
+ {
+ fprintf(stderr, "warning: connection could not be established to %s<%02x>\n",
+ cli_info.dest_host, cli_info.name_type);
+ fprintf(stderr, "this version of smbclient may crash if you proceed\n");
+ exit(-1);
+ }
+
+ switch (cli_action)
+ {
+ case CLIENT_IPC:
+ {
+ process(&cli_info, cmd_str) ? 0 : 1;
+ break;
+ }
+
+ default:
+ {
+ fprintf(stderr, "unknown client action requested\n");
+ break;
+ }
+ }
+
+ rpcclient_stop();
+
+ return(0);
+}
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..84a7e6fac05 100644
--- a/source/script/addtosmbpass
+++ b/source/script/addtosmbpass
@@ -48,11 +48,11 @@ BEGIN {
}
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/installbin.sh b/source/script/installbin.sh
index 633e6cb5bb2..22771ce5a07 100755
--- a/source/script/installbin.sh
+++ b/source/script/installbin.sh
@@ -1,4 +1,5 @@
#!/bin/sh
+
INSTALLPERMS=$1
BASEDIR=$2
BINDIR=$3
@@ -22,19 +23,22 @@ 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
+ mv $BINDIR/$p2 $BINDIR/$p2.old
fi
- cp $p $BINDIR/$p
- chmod $INSTALLPERMS $BINDIR/$p
+ cp $p $BINDIR/
+ chmod $INSTALLPERMS $BINDIR/$p2
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
diff --git a/source/script/installcp.sh b/source/script/installcp.sh
new file mode 100755
index 00000000000..87b0ef1a8ab
--- /dev/null
+++ b/source/script/installcp.sh
@@ -0,0 +1,38 @@
+#!/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
+ echo Creating codepage file $CODEPAGEDIR/codepage.$p
+ $BINDIR/make_smbcodepage c $p ${srcdir}/codepages/codepage_def.$p $CODEPAGEDIR/codepage.$p
+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..12a63e26c0d 100755
--- a/source/script/installman.sh
+++ b/source/script/installman.sh
@@ -1,6 +1,8 @@
#!/bin/sh
+#5 July 96 Dan.Shearer@unisa.edu.au removed hardcoded values
+
MANDIR=$1
-SRCDIR=$2
+SRCDIR=$2/
echo Installing man pages in $MANDIR
@@ -8,28 +10,30 @@ 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
+ echo Failed to make directory $d, does $USER have privileges?
exit 1
fi
fi
done
-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
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ echo Installing $FNAME
+ cp $s $m || echo Cannot create $FNAME... does $USER have privileges?
+ chmod 0644 $FNAME
+ 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
-echo Man pages installed
exit 0
diff --git a/source/script/installscripts.sh b/source/script/installscripts.sh
new file mode 100755
index 00000000000..6d55317e9e1
--- /dev/null
+++ b/source/script/installscripts.sh
@@ -0,0 +1,46 @@
+#!/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
+ 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..6bd11bcb99d
--- /dev/null
+++ b/source/script/installswat.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+#fist version March 1998, Andrew Tridgell
+
+SWATDIR=$1
+SRCDIR=$2/
+
+echo Installing SWAT in $SWATDIR
+
+echo Installing the Samba Web Admisistration Tool
+
+for d in $SWATDIR $SWATDIR/help $SWATDIR/images $SWATDIR/include; 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 f in $SRCDIR../swat/images/*.gif; do
+ FNAME=$SWATDIR/images/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+for f in $SRCDIR../swat/images/*.jpg; do
+ FNAME=$SWATDIR/images/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+for f in $SRCDIR../swat/help/*.html; do
+ FNAME=$SWATDIR/help/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+for f in $SRCDIR../swat/include/*.html; do
+ FNAME=$SWATDIR/include/`basename $f`
+ echo $FNAME
+ cp $f $FNAME || echo Cannot install $FNAME. Does $USER have privileges?
+ chmod 0644 $FNAME
+done
+
+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/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..dd8d4946a2b
--- /dev/null
+++ b/source/script/mkproto.awk
@@ -0,0 +1,116 @@
+BEGIN {
+ inheader=0;
+# use_ldap_define = 0;
+ current_file="";
+ print "#ifndef _PROTO_H_"
+ print "#define _PROTO_H_"
+ 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 (current_file=="ldap.c") {
+# print "#ifdef USE_LDAP"
+# use_ldap_define = 1;
+# }
+ }
+ if (inheader) {
+ if (match($0,"[)][ \t]*$")) {
+ inheader = 0;
+ printf "%s;\n",$0;
+ } else {
+ printf "%s\n",$0;
+ }
+ next;
+ }
+}
+
+# we handle the loadparm.c fns separately
+
+/^FN_LOCAL_BOOL/ {
+ split($0,a,"[,()]")
+ printf "BOOL %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_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 ~ /^connection_struct|^pipes_struct|^file_fd_struct|^files_struct|^connection_struct|^uid_t|^gid_t|^unsigned|^mode_t|^DIR|^user|^int|^pid_t/ ) {
+ gotstart = 1;
+ }
+
+ if( $0 ~ /^long|^char|^uint|^struct|^BOOL|^void|^time|^smb_shm_offset_t|^shm_offset_t|^enum remote_arch_types|^FILE|^SMB_OFF_T|^size_t|^ssize_t|^SMB_BIG_UINT/ ) {
+ gotstart = 1;
+ }
+ if(!gotstart) {
+ next;
+ }
+}
+
+
+/[(].*[)][ \t]*$/ {
+ printf "%s;\n",$0;
+ next;
+}
+
+/[(]/ {
+ inheader=1;
+ printf "%s\n",$0;
+ next;
+}
+
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/smbtar b/source/script/smbtar
index fc032ed41cd..25c36b2a8f7 100644
--- a/source/script/smbtar
+++ b/source/script/smbtar
@@ -6,13 +6,17 @@
# and Ricky Poulten (ricky@logcam.co.uk)
#
# (May need to change shell to ksh for HPUX or OSF for better getopts)
+#
+# 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
@@ -25,6 +29,7 @@ verbose="2>/dev/null" # Default: no echo to stdout
log="-d 2"
newer=""
blocksize=""
+clientargs="-c 'tarmode full'"
tarcmd="c"
tarargs=""
cdcmd="\\"
@@ -54,6 +59,16 @@ Options: (Description) (Default)
exit $ex
}
+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 rivl: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")
@@ -88,7 +103,7 @@ 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"
@@ -135,7 +150,6 @@ if [ -z "$verbose" ]; then
fi
eval $SMBCLIENT "'\\\\$server\\$service'" "'$password'" -U "'$username'" \
--E -N $log -D "'$cdcmd'" \
+-E -N $log -D "'$cdcmd'" ${clientargs} \
-T${tarcmd}${tarargs} $blocksize $newer $tapefile $* $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..bd7013c358f
--- /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/codepage.$p ]; then
+ echo $CPDIR/codepage.$p does not exist!
+ else
+ echo Removing $CPDIR/codepage.$p
+ rm -f $CPDIR/codepage.$p
+ if [ -f $CPDIR/codepage.$p ]; then
+ echo Cannot remove $CPDIR/codepage.$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..b6d2524ec77
--- /dev/null
+++ b/source/script/uninstallman.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+MANDIR=$1
+SRCDIR=$2
+
+echo Uninstalling man pages from $MANDIR
+
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR/../docs/*$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
+
+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..e69de29bb2d
--- /dev/null
+++ b/source/smbd/.cvsignore
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
new file mode 100644
index 00000000000..32b6d010a4f
--- /dev/null
+++ b/source/smbd/blocking.c
@@ -0,0 +1,624 @@
+/*
+ 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 int DEBUGLEVEL;
+extern int Client;
+extern int chain_size;
+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)
+{
+ free(blr->inbuf);
+ free((char *)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" ));
+ free((char *)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 \
+for fnum = %d, name = %s\n", length, (int)blr->expire_time,
+ 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);
+
+ send_smb(Client,outbuf);
+}
+
+/****************************************************************************
+ 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, int eclass, int32 ecode)
+{
+ char *outbuf = OutBuffer;
+ char *inbuf = blr->inbuf;
+ construct_reply_common(inbuf, outbuf);
+
+ if(eclass == 0) /* NT Error. */
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+
+ ERROR(eclass,ecode);
+ send_smb(Client,outbuf);
+}
+
+/****************************************************************************
+ 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, int eclass, int32 ecode)
+{
+ 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_OFF_T count = (SMB_OFF_T) 0, offset = (SMB_OFF_T) 0;
+ 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.
+ */
+
+ for(i = blr->lock_num; i >= 0; i--) {
+ int dummy1;
+ uint32 dummy2;
+ if(!large_file_format) {
+ count = IVAL(data,SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data,SMB_LKOFF_OFFSET(i));
+ }
+#ifdef LARGE_SMB_OFF_T
+ else {
+ count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
+ offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
+ }
+#endif /* LARGE_SMB_OFF_T */
+ do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
+ }
+
+ generic_blocking_lock_error(blr, eclass, ecode);
+}
+
+/****************************************************************************
+ Return a lock fail error.
+*****************************************************************************/
+
+static void blocking_lock_reply_error(blocking_lock_record *blr, int eclass, int32 ecode)
+{
+ switch(blr->com_type) {
+ case SMBlock:
+ generic_blocking_lock_error(blr, eclass, ecode);
+ break;
+ case SMBlockread:
+ generic_blocking_lock_error(blr, eclass, ecode);
+ break;
+ case SMBlockingX:
+ reply_lockingX_error(blr, eclass, ecode);
+ 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;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ size_t numtoread;
+ int eclass;
+ uint32 ecode;
+ 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;
+
+ if(!do_lock( fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode)) {
+ 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, eclass, ecode);
+ 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,ERRDOS,ERRnoaccess);
+ return True;
+ }
+
+ construct_reply_common(inbuf, outbuf);
+ outsize = set_message(outbuf,5,3,True);
+
+ outsize += nread;
+ SSVAL(outbuf,smb_vwv0,nread);
+ SSVAL(outbuf,smb_vwv5,nread+3);
+ SSVAL(smb_buf(outbuf),1,nread);
+
+ DEBUG(3, ( "process_lockread file = %s, fnum=%d num=%d nread=%d\n",
+ fsp->fsp_name, fsp->fnum, numtoread, 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;
+ int eclass;
+ uint32 ecode;
+ 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;
+ if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode)) {
+ 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, eclass, ecode);
+ 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_OFF_T count = 0, offset = 0;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ char *data;
+ int eclass=0;
+ uint32 ecode=0;
+
+ 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++) {
+ if(!large_file_format) {
+ count = IVAL(data,SMB_LKLEN_OFFSET(blr->lock_num));
+ offset = IVAL(data,SMB_LKOFF_OFFSET(blr->lock_num));
+ }
+#ifdef LARGE_SMB_OFF_T
+ else {
+ count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(blr->lock_num))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(blr->lock_num)));
+ offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(blr->lock_num))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(blr->lock_num)));
+ }
+#endif /* LARGE_SMB_OFF_T */
+ errno = 0;
+ if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK),
+ &eclass, &ecode))
+ 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, eclass, ecode);
+ 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,0,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);
+ }
+}
+
+/****************************************************************************
+ 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,ERRSRV,ERRaccess);
+ 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(!become_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,ERRSRV,ERRaccess);
+ 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(!become_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,ERRSRV,ERRaccess);
+ 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));
+ unbecome_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));
+ unbecome_user();
+ continue;
+ }
+
+ unbecome_user();
+
+ /*
+ * Move to the next in the list.
+ */
+ prev = blr;
+ blr = (blocking_lock_record *)ubi_slNext(blr);
+ }
+}
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index dc0514c1ed7..4131bc92971 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -1,3 +1,24 @@
+/*
+ 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.
@@ -27,41 +48,47 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
-#ifdef ALLOW_CHANGE_PASSWORD
-
+#if ALLOW_CHANGE_PASSWORD
#define MINPASSWDLENGTH 5
#define BUFSIZE 512
static int findpty(char **slave)
{
int master;
-#ifdef SVR4
- extern char *ptsname();
-#else
- static char line[12] = "/dev/ptyXX";
+#ifndef HAVE_GRANTPT
+ static fstring line;
void *dirp;
char *dpname;
-#endif
+#endif /* !HAVE_GRANTPT */
-#ifdef SVR4
+#if defined(HAVE_GRANTPT)
if ((master = open("/dev/ptmx", O_RDWR)) >= 1) {
grantpt(master);
unlockpt(master);
*slave = ptsname(master);
- return (master);
+ if(*slave == NULL) {
+ DEBUG(0,("findpty: Unable to create master/slave pty pair.\n"));
+ return -1;
+ } else {
+ DEBUG(10, ("findpty: Allocated slave pty %s\n", *slave));
+ return (master);
+ }
}
-#else
- dirp = OpenDir("/dev");
+#else /* HAVE_GRANTPT */
+ fstrcpy( line, "/dev/ptyXX" );
+
+ dirp = OpenDir(NULL, "/dev", False);
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 = open(line, O_RDWR)) >= 0) {
+ DEBUG(3,("pty: opened %s\n", line ) );
line[5] = 't';
*slave = line;
CloseDir(dirp);
@@ -70,21 +97,29 @@ static int findpty(char **slave)
}
}
CloseDir(dirp);
-#endif
+#endif /* HAVE_GRANTPT */
return (-1);
}
-static int dochild(int master,char *slavedev, char *name, char *passwordprogram)
+static int dochild(int master,char *slavedev, char *name, 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;
+ int gid;
+ int uid;
+
+ if(pass == NULL) {
+ DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n",
+ name));
+ return False;
+ }
-#ifdef USE_SETRES
+ gid = pass->pw_gid;
+ uid = pass->pw_uid;
+#ifdef HAVE_SETRESUID
setresuid(0,0,0);
-#else
+#else
setuid(0);
#endif
@@ -100,15 +135,15 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram)
slavedev));
return(False);
}
-#ifdef SVR4
+#ifdef I_PUSH
ioctl(slave, I_PUSH, "ptem");
ioctl(slave, I_PUSH, "ldterm");
-#else
+#elif defined(TIOCSCTTY)
if (ioctl(slave,TIOCSCTTY,0) <0) {
DEBUG(3,("Error in ioctl call for slave pty\n"));
/* return(False); */
}
-#endif
+#endif
/* Close master. */
close(master);
@@ -145,19 +180,23 @@ static int dochild(int master,char *slavedev, char *name, char *passwordprogram)
}
/* 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);
+ if(!as_root) {
+#ifdef HAVE_SETRESUID
+ 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);
+ setuid(0);
+ seteuid(0);
+ setgid(gid);
+ setegid(gid);
+ setuid(uid);
+ seteuid(uid);
#endif
+ }
+
+ DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram));
/* execl() password-change application */
if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) {
@@ -179,7 +218,7 @@ static int expect(int master,char *expected,char *buf)
}
/* allow 4 seconds for some output to appear */
- m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000, True);
+ m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000);
if (m < 0)
return False;
@@ -188,8 +227,8 @@ static int expect(int master,char *expected,char *buf)
{
pstring s1,s2;
- strcpy(s1,buf);
- strcpy(s2,expected);
+ pstrcpy(s1,buf);
+ pstrcpy(s2,expected);
if (do_match(s1, s2, False))
return(True);
}
@@ -223,30 +262,28 @@ static int talktochild(int master, char *chatsequence)
*buf = 0;
sleep(1);
- while (next_token(&ptr,chatbuf,NULL)) {
+ while (next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) {
BOOL ok=True;
count++;
pwd_sub(chatbuf);
if (!strequal(chatbuf,"."))
ok = expect(master,chatbuf,buf);
-#if DEBUG_PASSWORD
- DEBUG(100,("chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf));
-#endif
+ if(lp_passwd_chat_debug())
+ DEBUG(100,("talktochild: chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf));
if (!ok) {
DEBUG(3,("response %d incorrect\n",count));
return(False);
}
- if (!next_token(&ptr,chatbuf,NULL)) break;
+ if (!next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) break;
pwd_sub(chatbuf);
if (!strequal(chatbuf,"."))
writestring(master,chatbuf);
-#if DEBUG_PASSWORD
- DEBUG(100,("sendbuf=[%s]\n",chatbuf));
-#endif
+ if(lp_passwd_chat_debug())
+ DEBUG(100,("talktochild: sendbuf=[%s]\n",chatbuf));
}
if (count<1) return(False);
@@ -255,22 +292,23 @@ static int talktochild(int master, char *chatsequence)
}
-BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence)
+static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root)
{
char *slavedev;
int master;
pid_t pid, wpid;
int wstat;
- BOOL chstat;
+ BOOL chstat = False;
/* allocate a pseudo-terminal device */
if ((master = findpty (&slavedev)) < 0) {
- DEBUG(3,("Cannot Allocate pty for password change: %s",name));
+ DEBUG(3,("Cannot Allocate pty for password change: %s\n",name));
return(False);
}
if ((pid = fork()) < 0) {
- DEBUG(3,("Cannot fork() child for password change: %s",name));
+ DEBUG(3,("Cannot fork() child for password change: %s\n",name));
+ close(master);
return(False);
}
@@ -279,12 +317,16 @@ BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence)
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) {
+
+ if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
DEBUG(3,("The process is no longer waiting!\n\n"));
+ close(master);
return(False);
}
+
+ close(master);
+
if (pid != wpid) {
DEBUG(3,("We were waiting for the wrong process ID\n"));
return(False);
@@ -301,21 +343,36 @@ BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence)
} else {
/* CHILD */
+ /*
+ * Lose any oplock capabilities.
+ */
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
+
/* 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);
+ if(as_root)
+ become_root(False);
+ DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid()));
+ chstat = dochild(master, slavedev, name, passwordprogram, as_root);
+
+ if(as_root)
+ unbecome_root(False);
}
- DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name));
+
+ if(chstat)
+ DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name));
return (chstat);
}
-BOOL chgpasswd(char *name,char *oldpass,char *newpass)
+BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
{
pstring passwordprogram;
pstring chatsequence;
+ int i;
+ int len;
strlower(name);
DEBUG(3,("Password change for user: %s\n",name));
@@ -339,13 +396,8 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass)
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
+ pstrcpy(passwordprogram,lp_passwd_program());
+ pstrcpy(chatsequence,lp_passwd_chat());
if (!*chatsequence) {
DEBUG(2,("Null chat sequence - no password changing\n"));
@@ -357,6 +409,27 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass)
return(False);
}
+ /*
+ * 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;
+ }
+ }
+
string_sub(passwordprogram,"%u",name);
string_sub(passwordprogram,"%o",oldpass);
string_sub(passwordprogram,"%n",newpass);
@@ -364,13 +437,243 @@ BOOL chgpasswd(char *name,char *oldpass,char *newpass)
string_sub(chatsequence,"%u",name);
string_sub(chatsequence,"%o",oldpass);
string_sub(chatsequence,"%n",newpass);
- return(chat_with_program(passwordprogram,name,chatsequence));
+ return(chat_with_program(passwordprogram,name,chatsequence, as_root));
}
-#else
-BOOL chgpasswd(char *name,char *oldpass,char *newpass)
+#else /* ALLOW_CHANGE_PASSWORD */
+BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
{
DEBUG(0,("Password changing not compiled in (user=%s)\n",name));
return(False);
}
-#endif
+#endif /* ALLOW_CHANGE_PASSWORD */
+
+/***********************************************************
+ Code to check the lanman hashed password.
+************************************************************/
+
+BOOL check_lanman_password(char *user, unsigned char *pass1,
+ unsigned char *pass2, struct smb_passwd **psmbpw)
+{
+ unsigned char unenc_new_pw[16];
+ unsigned char unenc_old_pw[16];
+ unsigned char null_pw[16];
+ struct smb_passwd *smbpw;
+
+ *psmbpw = NULL;
+
+ become_root(0);
+ smbpw = getsmbpwnam(user);
+ unbecome_root(0);
+
+ if(smbpw == NULL)
+ {
+ DEBUG(0,("check_lanman_password: getsmbpwnam returned NULL\n"));
+ return False;
+ }
+
+ if(smbpw->acct_ctrl & ACB_DISABLED)
+ {
+ DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
+ return False;
+ }
+
+ if((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
+ {
+ unsigned char no_pw[14];
+ memset(no_pw, '\0', 14);
+ E_P16((uchar *)no_pw, (uchar *)null_pw);
+ smbpw->smb_passwd = null_pw;
+ } else if (smbpw->smb_passwd == NULL) {
+ DEBUG(0,("check_lanman_password: no lanman password !\n"));
+ return False;
+ }
+
+ /* Get the new lanman hash. */
+ D_P16(smbpw->smb_passwd, 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(smbpw->smb_passwd, unenc_old_pw, 16))
+ {
+ DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
+ return False;
+ }
+
+ *psmbpw = smbpw;
+ 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(struct smb_passwd *smbpw, unsigned char *pass1, unsigned char *pass2)
+{
+ unsigned char unenc_new_pw[16];
+ unsigned char null_pw[16];
+ BOOL ret;
+
+ if(smbpw == NULL)
+ {
+ DEBUG(0,("change_lanman_password: no smb password entry.\n"));
+ return False;
+ }
+
+ if(smbpw->acct_ctrl & ACB_DISABLED)
+ {
+ DEBUG(0,("change_lanman_password: account %s disabled.\n", smbpw->smb_name));
+ return False;
+ }
+
+ if((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
+ {
+ unsigned char no_pw[14];
+ memset(no_pw, '\0', 14);
+ E_P16((uchar *)no_pw, (uchar *)null_pw);
+ smbpw->smb_passwd = null_pw;
+ } else if (smbpw->smb_passwd == NULL) {
+ DEBUG(0,("change_lanman_password: no lanman password !\n"));
+ return False;
+ }
+
+ /* Get the new lanman hash. */
+ D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
+
+ smbpw->smb_passwd = unenc_new_pw;
+ smbpw->smb_nt_passwd = NULL; /* We lose the NT hash. Sorry. */
+
+ /* Now write it into the file. */
+ become_root(0);
+ ret = mod_smbpwd_entry(smbpw,False);
+ unbecome_root(0);
+
+ return ret;
+}
+
+/***********************************************************
+ Code to check the OEM hashed password.
+************************************************************/
+
+BOOL check_oem_password(char *user, unsigned char *data,
+ struct smb_passwd **psmbpw, char *new_passwd,
+ int new_passwd_size)
+{
+ struct smb_passwd *smbpw = NULL;
+ int new_pw_len;
+ fstring upper_case_new_passwd;
+ unsigned char new_p16[16];
+ unsigned char unenc_old_pw[16];
+ unsigned char null_pw[16];
+
+ become_root(0);
+ *psmbpw = smbpw = getsmbpwnam(user);
+ unbecome_root(0);
+
+ if(smbpw == NULL)
+ {
+ DEBUG(0,("check_oem_password: getsmbpwnam returned NULL\n"));
+ return False;
+ }
+
+ if(smbpw->acct_ctrl & ACB_DISABLED)
+ {
+ DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
+ return False;
+ }
+
+ if((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
+ {
+ unsigned char no_pw[14];
+ memset(no_pw, '\0', 14);
+ E_P16((uchar *)no_pw, (uchar *)null_pw);
+ smbpw->smb_passwd = null_pw;
+ } else if (smbpw->smb_passwd == NULL) {
+ DEBUG(0,("check_oem_password: no lanman password !\n"));
+ return False;
+ }
+
+ /*
+ * Call the hash function to get the new password.
+ */
+ SamOEMhash( (unsigned char *)data, (unsigned char *)smbpw->smb_passwd, True);
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+ new_pw_len = IVAL(data,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;
+ }
+
+ memcpy(new_passwd, &data[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.
+ */
+
+ memset(upper_case_new_passwd, '\0', sizeof(upper_case_new_passwd));
+ fstrcpy(upper_case_new_passwd, new_passwd);
+ strupper(upper_case_new_passwd);
+
+ E_P16((uchar *)upper_case_new_passwd, new_p16);
+
+ /*
+ * Now use new_p16 as the key to see if the old
+ * password matches.
+ */
+ D_P16(new_p16, &data[516], unenc_old_pw);
+
+ if(memcmp(smbpw->smb_passwd, unenc_old_pw, 16)) {
+ DEBUG(0,("check_oem_password: old password doesn't match.\n"));
+ return False;
+ }
+
+ memset(upper_case_new_passwd, '\0', strlen(upper_case_new_passwd));
+
+ return True;
+}
+
+/***********************************************************
+ Code to change the oem password. Changes both the lanman
+ and NT hashes.
+ override = False, normal
+ override = True, override XXXXXXXXXX'd password
+************************************************************/
+
+BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override)
+{
+ int ret;
+ fstring upper_case_new_passwd;
+ unsigned char new_nt_p16[16];
+ unsigned char new_p16[16];
+
+ memset(upper_case_new_passwd, '\0', sizeof(upper_case_new_passwd));
+ fstrcpy(upper_case_new_passwd, new_passwd);
+ strupper(upper_case_new_passwd);
+
+ E_P16((uchar *)upper_case_new_passwd, new_p16);
+
+ smbpw->smb_passwd = new_p16;
+
+ E_md4hash((uchar *) new_passwd, new_nt_p16);
+ smbpw->smb_nt_passwd = new_nt_p16;
+
+ /* Now write it into the file. */
+ become_root(0);
+ ret = mod_smbpwd_entry(smbpw,override);
+ unbecome_root(0);
+
+ memset(upper_case_new_passwd, '\0', strlen(upper_case_new_passwd));
+ memset(new_passwd, '\0', strlen(new_passwd));
+
+ return ret;
+}
diff --git a/source/smbd/close.c b/source/smbd/close.c
new file mode 100644
index 00000000000..981c0d77bb2
--- /dev/null
+++ b/source/smbd/close.c
@@ -0,0 +1,183 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+extern int32 global_oplocks_open;
+
+
+/****************************************************************************
+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(fsp->fsp_name,'/')))
+ p = fsp->fsp_name;
+ else
+ p++;
+
+ if (!strequal(lp_magicscript(SNUM(conn)),p))
+ return;
+ }
+
+ {
+ int ret;
+ pstring magic_output;
+ pstring fname;
+ 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,magic_output,False);
+ DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret));
+ unlink(fname);
+ }
+}
+
+/****************************************************************************
+ Common code to close a file or a directory.
+****************************************************************************/
+static void close_filestruct(files_struct *fsp)
+{
+ connection_struct *conn = fsp->conn;
+
+ fsp->open = False;
+ fsp->is_directory = False;
+
+ conn->num_files_open--;
+ if(fsp->wbmpx_ptr) {
+ free((char *)fsp->wbmpx_ptr);
+ fsp->wbmpx_ptr = NULL;
+ }
+
+#if WITH_MMAP
+ if(fsp->mmap_ptr) {
+ munmap(fsp->mmap_ptr,fsp->mmap_size);
+ fsp->mmap_ptr = NULL;
+ }
+#endif
+}
+
+/****************************************************************************
+ Close a file - possibly invalidating the read prediction.
+
+ 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.
+****************************************************************************/
+void close_file(files_struct *fsp, BOOL normal_close)
+{
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+ int token;
+ BOOL last_reference = False;
+ connection_struct *conn = fsp->conn;
+
+ remove_pending_lock_requests_by_fid(fsp);
+
+ close_filestruct(fsp);
+
+#if USE_READ_PREDICTION
+ invalidate_read_prediction(fsp->fd_ptr->fd);
+#endif
+
+ if (lp_share_modes(SNUM(conn))) {
+ lock_share_entry(conn, dev, inode, &token);
+ del_share_mode(token, fsp);
+ }
+
+ if(fd_attempt_close(fsp->fd_ptr) == 0)
+ last_reference = True;
+
+ fsp->fd_ptr = NULL;
+
+ if (lp_share_modes(SNUM(conn)))
+ unlock_share_entry(conn, dev, inode, token);
+
+ /* NT uses smbclose to start a print - weird */
+ if (normal_close && fsp->print_file)
+ print_file(conn, fsp);
+
+ /* check for magic scripts */
+ if (normal_close) {
+ check_magic(fsp,conn);
+ }
+
+ /*
+ * NT can set delete_on_close of the last open
+ * reference to a file.
+ */
+
+ if (normal_close && last_reference && fsp->delete_on_close) {
+ if(dos_unlink(fsp->fsp_name) != 0)
+ DEBUG(0,("close_file: file %s. Delete on close was set and unlink failed \
+with error %s\n", fsp->fsp_name, strerror(errno) ));
+ }
+
+ if(fsp->granted_oplock == True)
+ global_oplocks_open--;
+
+ fsp->sent_oplock_break = False;
+
+ DEBUG(2,("%s closed file %s (numopen=%d)\n",
+ conn->user,fsp->fsp_name,
+ conn->num_files_open));
+
+ if (fsp->fsp_name) {
+ string_free(&fsp->fsp_name);
+ }
+
+ file_free(fsp);
+}
+
+/****************************************************************************
+ Close a directory opened by an NT SMB call.
+****************************************************************************/
+
+void close_directory(files_struct *fsp)
+{
+ remove_pending_change_notify_requests_by_fid(fsp);
+
+ /*
+ * Do the code common to files and directories.
+ */
+ close_filestruct(fsp);
+
+ if (fsp->fsp_name)
+ string_free(&fsp->fsp_name);
+
+ file_free(fsp);
+}
+
diff --git a/source/smbd/conn.c b/source/smbd/conn.c
new file mode 100644
index 00000000000..5dc904bd91b
--- /dev/null
+++ b/source/smbd/conn.c
@@ -0,0 +1,189 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* 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_init(&conn->user,"");
+ string_init(&conn->dirpath,"");
+ string_init(&conn->connectpath,"");
+ string_init(&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)
+{
+ DLIST_REMOVE(Connections, conn);
+
+ if (conn->ngroups && conn->groups) {
+ free(conn->groups);
+ conn->groups = NULL;
+ conn->ngroups = 0;
+ }
+
+ 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);
+ free(conn);
+}
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
new file mode 100644
index 00000000000..0170fa54972
--- /dev/null
+++ b/source/smbd/connection.c
@@ -0,0 +1,224 @@
+/*
+ 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;
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+simple routines to do connection counting
+****************************************************************************/
+BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
+{
+ struct connect_record crec;
+ pstring fname;
+ int fd;
+ int mypid = getpid();
+ int i;
+
+ DEBUG(3,("Yielding connection to %s\n",name));
+
+ if (max_connections <= 0)
+ return(True);
+
+ bzero(&crec,sizeof(crec));
+
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,"","/");
+
+ pstrcat(fname,"/");
+ pstrcat(fname,name);
+ pstrcat(fname,".LCK");
+
+ fd = open(fname,O_RDWR);
+ if (fd == -1) {
+ DEBUG(2,("Couldn't open lock file %s (%s)\n",fname,strerror(errno)));
+ return(False);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: can't get lock on %s\n", fname));
+ return False;
+ }
+
+ /* find the right spot */
+ for (i=0;i<max_connections;i++) {
+ if (read(fd, &crec,sizeof(crec)) != sizeof(crec)) {
+ DEBUG(2,("Entry not found in lock file %s\n",fname));
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+ close(fd);
+ return(False);
+ }
+ if (crec.pid == mypid && crec.cnum == conn->cnum)
+ break;
+ }
+
+ if (crec.pid != mypid || crec.cnum != conn->cnum) {
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+ close(fd);
+ DEBUG(2,("Entry not found in lock file %s\n",fname));
+ return(False);
+ }
+
+ bzero((void *)&crec,sizeof(crec));
+
+ /* remove our mark */
+ if (sys_lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec) ||
+ write(fd, &crec,sizeof(crec)) != sizeof(crec)) {
+ DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno)));
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+ close(fd);
+ return(False);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+
+ DEBUG(3,("Yield successful\n"));
+
+ close(fd);
+ return(True);
+}
+
+
+/****************************************************************************
+simple routines to do connection counting
+****************************************************************************/
+BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
+{
+ extern int Client;
+ struct connect_record crec;
+ pstring fname;
+ int fd=-1;
+ 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));
+
+ pstrcpy(fname,lp_lockdir());
+ trim_string(fname,"","/");
+
+ if (!directory_exist(fname,NULL))
+ mkdir(fname,0755);
+
+ pstrcat(fname,"/");
+ pstrcat(fname,name);
+ pstrcat(fname,".LCK");
+
+ if (!file_exist(fname,NULL)) {
+ fd = open(fname,O_RDWR|O_CREAT|O_EXCL, 0644);
+ }
+
+ if (fd == -1) {
+ fd = open(fname,O_RDWR);
+ }
+
+ if (fd == -1) {
+ DEBUG(1,("couldn't open lock file %s\n",fname));
+ return(False);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_WRLCK)==False) {
+ DEBUG(0,("ERROR: can't get lock on %s\n", fname));
+ return False;
+ }
+
+ total_recs = file_size(fname) / sizeof(crec);
+
+ /* find a free spot */
+ for (i=0;i<max_connections;i++) {
+ if (i>=total_recs ||
+ sys_lseek(fd,i*sizeof(crec),SEEK_SET) != i*sizeof(crec) ||
+ read(fd,&crec,sizeof(crec)) != sizeof(crec)) {
+ if (foundi < 0) foundi = i;
+ break;
+ }
+
+ if (Clear && crec.pid && !process_exists(crec.pid)) {
+ sys_lseek(fd,i*sizeof(crec),SEEK_SET);
+ bzero((void *)&crec,sizeof(crec));
+ write(fd, &crec,sizeof(crec));
+ if (foundi < 0) foundi = i;
+ continue;
+ }
+ if (foundi < 0 && (!crec.pid || !process_exists(crec.pid))) {
+ foundi=i;
+ if (!Clear) break;
+ }
+ }
+
+ if (foundi < 0) {
+ DEBUG(3,("no free locks in %s\n",fname));
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+ close(fd);
+ return(False);
+ }
+
+ /* fill in the crec */
+ bzero((void *)&crec,sizeof(crec));
+ crec.magic = 0x280267;
+ crec.pid = getpid();
+ if (conn) {
+ crec.cnum = conn->cnum;
+ crec.uid = conn->uid;
+ crec.gid = conn->gid;
+ StrnCpy(crec.name,
+ lp_servicename(SNUM(conn)),sizeof(crec.name)-1);
+ } else {
+ crec.cnum = -1;
+ }
+ crec.start = time(NULL);
+
+ StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
+ StrnCpy(crec.addr,client_addr(Client),sizeof(crec.addr)-1);
+
+ /* make our mark */
+ if (sys_lseek(fd,foundi*sizeof(crec),SEEK_SET) != foundi*sizeof(crec) ||
+ write(fd, &crec,sizeof(crec)) != sizeof(crec)) {
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+ close(fd);
+ return(False);
+ }
+
+ if (fcntl_lock(fd,SMB_F_SETLKW,0,1,F_UNLCK)==False) {
+ DEBUG(0,("ERROR: can't release lock on %s\n", fname));
+ }
+
+ close(fd);
+ return(True);
+}
diff --git a/source/smbd/dfree.c b/source/smbd/dfree.c
new file mode 100644
index 00000000000..c96a599e77b
--- /dev/null
+++ b/source/smbd/dfree.c
@@ -0,0 +1,229 @@
+/*
+ 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"
+
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+normalise for DOS usage
+****************************************************************************/
+static void disk_norm(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 (*bsize > WORDMAX) {
+ *bsize = WORDMAX;
+ if (*dsize > WORDMAX)
+ *dsize = WORDMAX;
+ if (*dfree > WORDMAX)
+ *dfree = WORDMAX;
+ break;
+ }
+ }
+}
+
+
+/* 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
+*/
+static int 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 */
+
+#ifdef STAT_STATVFS /* 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;
+}
+
+/****************************************************************************
+ return number of 1K blocks available on a path and total number
+****************************************************************************/
+static SMB_BIG_UINT disk_free(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ int dfree_retval;
+
+ (*dfree) = (*dsize) = 0;
+ (*bsize) = 512;
+
+ fsusage(path, dfree, dsize);
+
+ if (*bsize < 256) {
+ *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(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(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
+{
+ return(disk_free(dos_to_unix(path,False),bsize,dfree,dsize));
+}
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index ac6f918b9da..03864334eb8 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,10 +20,8 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
-extern connection_struct Connections[];
/*
This module implements directory related functions for Samba.
@@ -31,24 +29,23 @@ extern connection_struct Connections[];
-uint32 dircounter = 0;
+static 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;
+static struct dptr_struct {
+ int pid;
+ connection_struct *conn;
+ uint32 lastused;
+ void *ptr;
+ BOOL valid;
+ BOOL finished;
+ BOOL expect_close;
+ char *wcard; /* Field only used for trans2_ searches */
+ uint16 attr; /* Field only used for trans2_ searches */
+ char *path;
}
dirptrs[NUMDIRPTRS];
@@ -111,18 +108,20 @@ get the dir ptr 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++;
- }
- return(dirptrs[key].ptr);
- }
- return(NULL);
+ struct dptr_struct *dp = &dirptrs[key];
+
+ if (dp->valid) {
+ if (lastused) dp->lastused = lastused;
+ if (!dp->ptr) {
+ if (dptrs_open >= MAX_OPEN_DIRECTORIES)
+ dptr_idleoldest();
+ DEBUG(4,("Reopening dptr key %d\n",key));
+ if ((dp->ptr = OpenDir(dp->conn, dp->path, True)))
+ dptrs_open++;
+ }
+ return(dp->ptr);
+ }
+ return(NULL);
}
/****************************************************************************
@@ -186,6 +185,19 @@ close a dptr
****************************************************************************/
void dptr_close(int key)
{
+ /* OS/2 seems to use -1 to indicate "close all directories" */
+ if (key == -1) {
+ int i;
+ for (i=0;i<NUMDIRPTRS;i++)
+ dptr_close(i);
+ return;
+ }
+
+ if (key < 0 || key >= NUMDIRPTRS) {
+ DEBUG(3,("Invalid key %d given to dptr_close\n",key));
+ return;
+ }
+
if (dirptrs[key].valid) {
DEBUG(4,("closing dptr key %d\n",key));
if (dirptrs[key].ptr) {
@@ -203,22 +215,22 @@ void dptr_close(int key)
/****************************************************************************
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)
+ if (dirptrs[i].valid && dirptrs[i].conn == conn)
dptr_close(i);
}
/****************************************************************************
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)
+ if (dirptrs[i].valid && dirptrs[i].conn == conn && dirptrs[i].ptr)
dptr_idle(i);
}
@@ -237,40 +249,40 @@ void dptr_closepath(char *path,int pid)
/****************************************************************************
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))
- return(False);
+ if (!check_name(directory,conn))
+ return(False);
- if (! *directory)
- directory = ".";
-
- Connections[cnum].dirptr = OpenDir(directory);
- if (Connections[cnum].dirptr) {
- dptrs_open++;
- string_set(&Connections[cnum].dirpath,directory);
- return(True);
- }
+ if (! *directory)
+ directory = ".";
+
+ conn->dirptr = OpenDir(conn, directory, True);
+ if (conn->dirptr) {
+ dptrs_open++;
+ string_set(&conn->dirpath,directory);
+ return(True);
+ }
- return(False);
+ return(False);
}
/****************************************************************************
create a new dir ptr
****************************************************************************/
-int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
+int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
{
int i;
uint32 old;
int oldi;
- 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++)
@@ -311,11 +323,11 @@ int dptr_create(int cnum,char *path, BOOL expect_close,int pid)
if (dirptrs[i].valid)
dptr_close(i);
- dirptrs[i].ptr = Connections[cnum].dirptr;
+ dirptrs[i].ptr = conn->dirptr;
string_set(&dirptrs[i].path,path);
dirptrs[i].lastused = dircounter++;
dirptrs[i].finished = False;
- dirptrs[i].cnum = cnum;
+ dirptrs[i].conn = conn;
dirptrs[i].pid = pid;
dirptrs[i].expect_close = expect_close;
dirptrs[i].wcard = NULL; /* Only used in lanman2 searches */
@@ -343,7 +355,7 @@ BOOL dptr_fill(char *buf1,unsigned int 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 %d dirptr 0x%x now at %d\n",key,(unsigned)p,offset));
buf[0] = key;
SIVAL(buf,1,offset | DPTR_MASK);
return(True);
@@ -379,77 +391,85 @@ 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);
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);
}
/****************************************************************************
+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 a 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)));
+ (unsigned)conn->dirptr,TellDir(conn->dirptr)));
if (dname == NULL)
return(False);
- matched = False;
-
- strcpy(filename,dname);
+ pstrcpy(filename,dname);
if ((strcmp(filename,mask) == 0) ||
- (name_map_mangle(filename,True,SNUM(cnum)) &&
+ (name_map_mangle(filename,True,SNUM(conn)) &&
mask_match(filename,mask,False,False)))
{
if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
continue;
- strcpy(fname,filename);
+ pstrcpy(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)
+ pstrcpy(path,conn->dirpath);
+ if(needslash)
+ pstrcat(path,"/");
+ pstrcpy(pathreal,path);
+ pstrcat(path,fname);
+ pstrcat(pathreal,dname);
+ if (dos_stat(pathreal,&sbuf) != 0)
{
DEBUG(5,("Couldn't stat 1 [%s]\n",path));
continue;
@@ -459,13 +479,13 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
!strequal(fname,".") && !strequal(fname,".."))
continue;
- *mode = dos_mode(cnum,pathreal,&sbuf);
+ *mode = dos_mode(conn,pathreal,&sbuf);
+
+ if (!dir_check_ftype(conn,*mode,&sbuf,dirtype)) {
+ DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
+ continue;
+ }
- 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;
@@ -493,11 +513,11 @@ typedef struct
/*******************************************************************
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);
+ void *p = dos_opendir(name);
int used=0;
if (!p) return(NULL);
@@ -509,8 +529,13 @@ void *OpenDir(char *name)
dirp->pos = dirp->numentries = dirp->mallocsize = 0;
dirp->data = dirp->current = NULL;
- while ((n = readdirname(p))) {
+ while ((n = readdirname(p)))
+ {
int 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;
+
if (used + l > dirp->mallocsize) {
int s = MAX(used+l,used+2000);
char *r;
@@ -523,7 +548,7 @@ 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++;
}
@@ -594,362 +619,132 @@ int TellDir(void *p)
}
-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++;
- }
-}
+/* -------------------------------------------------------------------------- **
+ * 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 );
+
+void DirCacheAdd( char *path, char *name, char *dname, int snum )
+ /* ------------------------------------------------------------------------ **
+ * Add an entry to the directory cache.
+ *
+ * Input: path -
+ * name -
+ * dname -
+ * snum -
+ *
+ * Output: None.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ 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 )
+ free( ubi_dlRemTail( dir_cache ) );
+
+ } /* DirCacheAdd */
+
+
+char *DirCacheCheck( char *path, char *name, int snum )
+ /* ------------------------------------------------------------------------ **
+ * 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.
+ *
+ * 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.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ dir_cache_entry *entry;
-/*******************************************************************
-check for an entry in the directory cache
-********************************************************************/
-char *DirCacheCheck(char *path,char *name,int snum)
-{
- struct dir_cache *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);
-}
+ } /* DirCacheCheck */
-/*******************************************************************
-flush entries in the dir_cache
-********************************************************************/
void DirCacheFlush(int snum)
+ /* ------------------------------------------------------------------------ **
+ * Remove all cache entries which have an snum that matches the input.
+ *
+ * Input: snum -
+ *
+ * Output: None.
+ *
+ * ------------------------------------------------------------------------ **
+ */
{
- 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 )
+ 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;
- }
+} /* DirCacheFlush */
- 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);
+/* -------------------------------------------------------------------------- **
+ * End of the section that manages the global directory cache.
+ * -------------------------------------------------------------------------- **
+ */
- 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..b74e11e643d
--- /dev/null
+++ b/source/smbd/dosmode.c
@@ -0,0 +1,259 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+ 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
+ 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
+ Then apply create mask,
+ then add force bits.
+****************************************************************************/
+mode_t unix_mode(connection_struct *conn,int dosmode)
+{
+ 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)) {
+ /* 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_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
+ /* Apply directory mask */
+ result &= lp_dir_mode(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;
+
+ /* Apply mode mask */
+ result &= lp_create_mode(SNUM(conn));
+ /* Add in force bits */
+ result |= lp_force_create_mode(SNUM(conn));
+ }
+ 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(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;
+
+ if (!st) {
+ st = &st1;
+ if (dos_stat(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);
+
+ /* 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
+ 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(dos_chmod(fname,unixmode));
+}
+
+
+/*******************************************************************
+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(dos_utime(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(dos_stat(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(False);
+ ret = dos_utime(fname, times);
+ unbecome_root(False);
+ }
+ }
+
+ 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(True);
+}
+
+
diff --git a/source/smbd/error.c b/source/smbd/error.c
new file mode 100644
index 00000000000..d879f9a93c4
--- /dev/null
+++ b/source/smbd/error.c
@@ -0,0 +1,146 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* 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 *inbuf,char *outbuf,files_struct *fsp,int line)
+{
+ 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(inbuf,outbuf,eclass,err,line);
+}
+
+
+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 *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 != 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(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 = CVAL(inbuf,smb_com);
+ int flgs2 = SVAL(outbuf,smb_flg2);
+
+ if ((flgs2 & FLAGS2_32_BIT_ERROR_CODES) == FLAGS2_32_BIT_ERROR_CODES)
+ {
+ SIVAL(outbuf,smb_rcls,error_code);
+
+ DEBUG( 3, ( "32 bit error packet at line %d cmd=%d (%s) eclass=%08x [%s]\n",
+ line, cmd, smb_fn_name(cmd), error_code, smb_errstr(outbuf) ) );
+ }
+ else
+ {
+ CVAL(outbuf,smb_rcls) = error_class;
+ SSVAL(outbuf,smb_err,error_code);
+ DEBUG( 3, ( "error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
+ 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);
+}
diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c
new file mode 100644
index 00000000000..5c4bf7dfc23
--- /dev/null
+++ b/source/smbd/fileio.c
@@ -0,0 +1,129 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+
+/****************************************************************************
+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;
+
+ if (fsp->print_file && lp_postscript(fsp->conn->service))
+ offset = 3;
+
+ fsp->pos = (sys_lseek(fsp->fd_ptr->fd,pos+offset,SEEK_SET) - offset);
+
+ DEBUG(10,("seek_file: requested pos = %.0f, new pos = %.0f\n",
+ (double)(pos+offset), (double)fsp->pos ));
+
+ return(fsp->pos);
+}
+
+/****************************************************************************
+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;
+
+#if USE_READ_PREDICTION
+ if (!fsp->can_write) {
+ ret = read_predict(fsp->fd_ptr->fd,pos,data,NULL,n);
+
+ data += ret;
+ n -= ret;
+ pos += ret;
+ }
+#endif
+
+#if WITH_MMAP
+ if (fsp->mmap_ptr) {
+ SMB_OFF_T num = (fsp->mmap_size > pos) ? (fsp->mmap_size - pos) : -1;
+ num = MIN(n,num);
+ if (num > 0) {
+ memcpy(data,fsp->mmap_ptr+pos,num);
+ data += num;
+ pos += num;
+ n -= num;
+ ret += num;
+ }
+ }
+#endif
+
+ if (seek_file(fsp,pos) != pos) {
+ DEBUG(3,("read_file: Failed to seek to %.0f\n",(double)pos));
+ return(ret);
+ }
+
+ if (n > 0) {
+ readret = read(fsp->fd_ptr->fd,data,n);
+ if (readret > 0) ret += readret;
+ }
+
+ return(ret);
+}
+
+
+/****************************************************************************
+write to a file
+****************************************************************************/
+
+ssize_t write_file(files_struct *fsp,char *data,size_t n)
+{
+
+ if (!fsp->can_write) {
+ errno = EPERM;
+ return(0);
+ }
+
+ if (!fsp->modified) {
+ SMB_STRUCT_STAT st;
+ fsp->modified = True;
+ if (sys_fstat(fsp->fd_ptr->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);
+ }
+ }
+ }
+
+ return(write_data(fsp->fd_ptr->fd,data,n));
+}
+
+
+/*******************************************************************
+sync a file
+********************************************************************/
+
+void sync_file(connection_struct *conn, files_struct *fsp)
+{
+#ifdef HAVE_FSYNC
+ if(lp_strict_sync(SNUM(conn)))
+ fsync(fsp->fd_ptr->fd);
+#endif
+}
diff --git a/source/smbd/filename.c b/source/smbd/filename.c
new file mode 100644
index 00000000000..ff4d6827477
--- /dev/null
+++ b/source/smbd/filename.c
@@ -0,0 +1,729 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ filename handling 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"
+
+extern int DEBUGLEVEL;
+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)
+{
+ pstring tmpname;
+
+ if (is_8_3(name2, True))
+ return(False);
+
+ pstrcpy(tmpname,name2);
+ mangle_name_83(tmpname);
+
+ return(strequal(name1,tmpname));
+}
+
+/****************************************************************************
+ Stat cache code used in unix_convert.
+*****************************************************************************/
+
+static int global_stat_cache_lookups;
+static int global_stat_cache_misses;
+static int global_stat_cache_hits;
+
+/****************************************************************************
+ Stat cache statistics code.
+*****************************************************************************/
+
+void print_stat_cache_statistics(void)
+{
+ double eff = (100.0* (double)global_stat_cache_hits)/(double)global_stat_cache_lookups;
+
+ DEBUG(0,("stat cache stats: lookups = %d, hits = %d, misses = %d, \
+stat cache was %f%% effective.\n", global_stat_cache_lookups,
+ global_stat_cache_hits, global_stat_cache_misses, eff ));
+}
+
+typedef struct {
+ ubi_dlNode link;
+ int name_len;
+ pstring orig_name;
+ pstring translated_name;
+} stat_cache_entry;
+
+#define MAX_STAT_CACHE_SIZE 50
+
+static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
+
+/****************************************************************************
+ Compare a pathname to a name in the stat cache - of a given length.
+ Note - this code always checks that the next character in the pathname
+ is either a '/' character, or a '\0' character - to ensure we only
+ match *full* pathname components. Note we don't need to handle case
+ here, if we're case insensitive the stat cache orig names are all upper
+ case.
+*****************************************************************************/
+
+static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
+{
+ BOOL matched = (memcmp( stat_name, orig_name, len) == 0);
+ if(orig_name[len] != '/' && orig_name[len] != '\0')
+ return False;
+
+ return matched;
+}
+
+/****************************************************************************
+ Add an entry into the stat cache.
+*****************************************************************************/
+
+static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
+{
+ stat_cache_entry *scp;
+ pstring orig_name;
+ pstring translated_path;
+ int namelen;
+
+ 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.
+ */
+
+ for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
+ scp = (stat_cache_entry *)ubi_dlNext( scp )) {
+ if((strcmp( scp->orig_name, orig_name) == 0) &&
+ (strcmp( scp->translated_name, translated_path) == 0)) {
+ /*
+ * Name does exist - promote it.
+ */
+ if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != scp ) {
+ ubi_dlRemThis( &stat_cache, scp);
+ ubi_dlAddHead( &stat_cache, scp);
+ }
+ return;
+ }
+ }
+
+ if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry))) == NULL) {
+ DEBUG(0,("stat_cache_add: Out of memory !\n"));
+ return;
+ }
+
+ pstrcpy(scp->orig_name, orig_name);
+ pstrcpy(scp->translated_name, translated_path);
+ scp->name_len = namelen;
+
+ ubi_dlAddHead( &stat_cache, scp);
+
+ DEBUG(10,("stat_cache_add: Added entry %s -> %s\n", scp->orig_name, scp->translated_name ));
+
+ if(ubi_dlCount(&stat_cache) > lp_stat_cache_size()) {
+ scp = (stat_cache_entry *)ubi_dlRemTail( &stat_cache );
+ free((char *)scp);
+ return;
+ }
+}
+
+/****************************************************************************
+ 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.
+*****************************************************************************/
+
+static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRUCT_STAT *pst)
+{
+ stat_cache_entry *scp;
+ stat_cache_entry *longest_hit = NULL;
+ pstring chk_name;
+ int namelen;
+
+ if (!lp_stat_cache()) return False;
+
+ namelen = strlen(name);
+
+ *start = name;
+ global_stat_cache_lookups++;
+
+ /*
+ * Don't lookup trivial valid directory entries.
+ */
+ if((*name == '\0') || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
+ global_stat_cache_misses++;
+ return False;
+ }
+
+ pstrcpy(chk_name, name);
+ if(!case_sensitive)
+ strupper( chk_name );
+
+ for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp;
+ scp = (stat_cache_entry *)ubi_dlNext( scp )) {
+ if(scp->name_len <= namelen) {
+ if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) {
+ if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len))
+ longest_hit = scp;
+ }
+ }
+ }
+
+ if(longest_hit == NULL) {
+ DEBUG(10,("stat_cache_lookup: cache miss on %s\n", name));
+ global_stat_cache_misses++;
+ return False;
+ }
+
+ global_stat_cache_hits++;
+
+ DEBUG(10,("stat_cache_lookup: cache hit for name %s. %s -> %s\n",
+ name, longest_hit->orig_name, longest_hit->translated_name ));
+
+ /*
+ * longest_hit is the longest match we got in the list.
+ * Check it exists - if so, overwrite the original name
+ * and then promote it to the top.
+ */
+
+ if(dos_stat( longest_hit->translated_name, pst) != 0) {
+ /*
+ * Discard this entry.
+ */
+ ubi_dlRemThis( &stat_cache, longest_hit);
+ free((char *)longest_hit);
+ return False;
+ }
+
+ memcpy(name, longest_hit->translated_name, longest_hit->name_len);
+ if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != longest_hit ) {
+ ubi_dlRemThis( &stat_cache, longest_hit);
+ ubi_dlAddHead( &stat_cache, longest_hit);
+ }
+
+ *start = &name[longest_hit->name_len];
+ if(**start == '/')
+ ++*start;
+
+ StrnCpy( dirpath, longest_hit->translated_name, name - (*start));
+
+ return (namelen == longest_hit->name_len);
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+
+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;
+ int saved_errno;
+ BOOL component_was_mangled = False;
+ BOOL name_has_wildcard = False;
+#if 0
+ /* Andrew's conservative code... JRA. */
+ extern char magic_char;
+#endif
+
+ *dirpath = 0;
+ *bad_path = False;
+ if(pst) {
+ ZERO_STRUCTP(pst);
+ }
+
+ if(saved_last_component)
+ *saved_last_component = 0;
+
+ /*
+ * 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,"/","/");
+
+ /*
+ * Ensure saved_last_component is valid even if file exists.
+ */
+
+ if(saved_last_component) {
+ end = strrchr(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);
+
+ /*
+ * Check if it's a printer file.
+ */
+ if (conn->printer) {
+ if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) {
+ char *s;
+ fstring name2;
+ slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine);
+
+ /*
+ * Sanitise the name.
+ */
+
+ for (s=name2 ; *s ; s++)
+ if (!issafe(*s)) *s = '_';
+ pstrcpy(name,(char *)mktemp(name2));
+ }
+ return(True);
+ }
+
+ /*
+ * 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( name, dirpath, &start, &st)) {
+ if(pst)
+ *pst = st;
+ return True;
+ }
+
+ /*
+ * stat the name - if it exists then we are all done!
+ */
+
+ if (dos_stat(name,&st) == 0) {
+ stat_cache_add(orig_path, name);
+ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
+ if(pst)
+ *pst = st;
+ return(True);
+ }
+
+ saved_errno = errno;
+
+ 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 && (saved_errno != ENOENT))
+ return(False);
+
+ if(strchr(start,'?') || strchr(start,'*'))
+ name_has_wildcard = True;
+
+ /*
+ * is_mangled() was changed to look at an entire pathname, not
+ * just a component. JRA.
+ */
+
+ if(is_mangled(start))
+ component_was_mangled = True;
+
+#if 0
+ /* Keep Andrew's conservative code around, just in case. JRA. */
+ /* this is an extremely conservative test for mangled names. */
+ if (strchr(start,magic_char))
+ component_was_mangled = True;
+#endif
+
+ /*
+ * 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(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 (dos_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;
+
+ *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 (strchr(start,'?') || strchr(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 (end) {
+ pstrcpy(start+strlen(start)+1,rest);
+ end = start + strlen(start);
+ }
+ } /* 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);
+
+ /*
+ * 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(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 ( (dos_lstat(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,SNUM(conn))) 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(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..e8b391d1175
--- /dev/null
+++ b/source/smbd/files.c
@@ -0,0 +1,496 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* the only restriction is that this must be less than PIPE_HANDLE_OFFSET */
+#define MAX_FNUMS 4096
+
+#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < MAX_FNUMS))
+
+#define FILE_HANDLE_OFFSET 0x1000
+
+static struct bitmap *file_bmap;
+
+#ifdef USE_FILES_ARRAY
+static files_struct *Files[MAX_FNUMS];
+#else
+static files_struct *Files;
+#endif
+
+/* 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;
+
+/*
+ * Indirection for file fd's. Needed as POSIX locking
+ * is based on file/process, not fd/process.
+ */
+static file_fd_struct *FileFd;
+
+static int files_used, fd_ptr_used;
+
+/****************************************************************************
+ find first available file slot
+****************************************************************************/
+files_struct *file_new(void )
+{
+ 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 = (getpid() ^ (int)time(NULL)) % MAX_FNUMS;
+ }
+
+ 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.
+ */
+#ifdef USE_FILES_ARRAY
+ for(i = 0; i < MAX_FNUMS; i++) {
+ if((fsp = Files[i]) == NULL)
+ continue;
+ if (attempt_close_oplocked_file(fsp))
+ return file_new();
+ }
+#else
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if (attempt_close_oplocked_file(fsp)) {
+ return file_new();
+ }
+ }
+#endif
+
+ DEBUG(0,("ERROR! Out of file structures\n"));
+ return NULL;
+ }
+
+ fsp = (files_struct *)malloc(sizeof(*fsp));
+ if (!fsp) return NULL;
+
+ ZERO_STRUCTP(fsp);
+
+ first_file = (i+1) % MAX_FNUMS;
+
+ bitmap_set(file_bmap, i);
+ files_used++;
+
+ fsp->fnum = i + FILE_HANDLE_OFFSET;
+ string_init(&fsp->fsp_name,"");
+
+#ifdef USE_FILES_ARRAY
+ Files[i] = fsp;
+#else
+ DLIST_ADD(Files, fsp);
+#endif
+
+ DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
+ i, fsp->fnum, files_used));
+
+ chain_fsp = fsp;
+
+ return fsp;
+}
+
+
+
+/****************************************************************************
+fd support routines - attempt to find an already open file by dev
+and inode - increments the ref_count of the returned file_fd_struct *.
+****************************************************************************/
+file_fd_struct *fd_get_already_open(SMB_STRUCT_STAT *sbuf)
+{
+ file_fd_struct *fd_ptr;
+
+ if(!sbuf) return NULL;
+
+ for (fd_ptr=FileFd;fd_ptr;fd_ptr=fd_ptr->next) {
+ if ((fd_ptr->ref_count > 0) &&
+ (sbuf->st_dev == fd_ptr->dev) &&
+ (sbuf->st_ino == fd_ptr->inode)) {
+ fd_ptr->ref_count++;
+
+ DEBUG(3,("Re-used file_fd_struct dev = %x, inode = %.0f, ref_count = %d\n",
+ (unsigned int)fd_ptr->dev, (double)fd_ptr->inode,
+ fd_ptr->ref_count));
+
+ return fd_ptr;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/****************************************************************************
+fd support routines - attempt to find a empty slot in the FileFd array.
+Increments the ref_count of the returned entry.
+****************************************************************************/
+file_fd_struct *fd_get_new(void)
+{
+ extern struct current_user current_user;
+ file_fd_struct *fd_ptr;
+
+ fd_ptr = (file_fd_struct *)malloc(sizeof(*fd_ptr));
+ if (!fd_ptr) {
+ DEBUG(0,("ERROR! malloc fail for file_fd struct.\n"));
+ return NULL;
+ }
+
+ ZERO_STRUCTP(fd_ptr);
+
+ fd_ptr->dev = (SMB_DEV_T)-1;
+ fd_ptr->inode = (SMB_INO_T)-1;
+ fd_ptr->fd = -1;
+ fd_ptr->fd_readonly = -1;
+ fd_ptr->fd_writeonly = -1;
+ fd_ptr->real_open_flags = -1;
+ fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
+ fd_ptr->ref_count++;
+
+ fd_ptr_used++;
+
+ DLIST_ADD(FileFd, fd_ptr);
+
+ DEBUG(5,("allocated fd_ptr structure (%d used)\n", fd_ptr_used));
+
+ return fd_ptr;
+}
+
+
+/****************************************************************************
+close all open files for a connection
+****************************************************************************/
+void file_close_conn(connection_struct *conn)
+{
+ files_struct *fsp, *next;
+
+#ifdef USE_FILES_ARRAY
+ int i;
+ for (i = 0; i < MAX_FNUMS; i++) {
+ if((fsp = Files[i]) == NULL)
+ continue;
+ if(fsp->conn == conn && fsp->open) {
+ if (fsp->is_directory)
+ close_directory(fsp);
+ else
+ close_file(fsp,False);
+ }
+ }
+#else
+ for (fsp=Files;fsp;fsp=next) {
+ next = fsp->next;
+ if (fsp->conn == conn && fsp->open) {
+ if (fsp->is_directory)
+ close_directory(fsp);
+ else
+ close_file(fsp,False);
+ }
+ }
+#endif
+}
+
+/****************************************************************************
+initialise file structures
+****************************************************************************/
+void file_init(void)
+{
+ file_bmap = bitmap_allocate(MAX_FNUMS);
+
+ if (!file_bmap) {
+ exit_server("out of memory in file_init");
+ }
+
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ {
+ struct rlimit rlp;
+ getrlimit(RLIMIT_NOFILE, &rlp);
+ /* Set the fd limit to be MAX_FNUMS + 10 to
+ * account for the extra fd we need
+ * as well as the log files and standard
+ * handles etc. */
+ rlp.rlim_cur = (MAX_FNUMS+10>rlp.rlim_max)?
+ rlp.rlim_max:MAX_FNUMS+10;
+ setrlimit(RLIMIT_NOFILE, &rlp);
+ getrlimit(RLIMIT_NOFILE, &rlp);
+ DEBUG(3,("Maximum number of open files per session is %d\n",
+ (int)rlp.rlim_cur));
+ }
+#endif
+}
+
+
+/****************************************************************************
+close files open by a specified vuid
+****************************************************************************/
+void file_close_user(int vuid)
+{
+ files_struct *fsp, *next;
+
+#ifdef USE_FILES_ARRAY
+ int i;
+ for(i = 0; i < MAX_FNUMS; i++) {
+ if((fsp = Files[i]) == NULL)
+ continue;
+ if((fsp->vuid == vuid) && fsp->open) {
+ if(!fsp->is_directory)
+ close_file(fsp,False);
+ else
+ close_directory(fsp);
+ }
+ }
+#else
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if ((fsp->vuid == vuid) && fsp->open) {
+ if(!fsp->is_directory)
+ close_file(fsp,False);
+ else
+ close_directory(fsp);
+ }
+ }
+#endif
+}
+
+
+/****************************************************************************
+ Find a fsp given a device, inode and timevalue
+ If this is from a kernel oplock break request then tval may be NULL.
+****************************************************************************/
+
+files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+{
+ int count=0;
+ files_struct *fsp;
+
+#ifdef USE_FILES_ARRAY
+ for(count = 0; count < MAX_FNUMS; count++) {
+ if((fsp = Files[count]) == NULL)
+ continue;
+ if (fsp->open &&
+ fsp->fd_ptr->dev == dev &&
+ fsp->fd_ptr->inode == inode &&
+ (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True) &&
+ (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True))
+ return fsp;
+ }
+#else
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ if (fsp->open &&
+ fsp->fd_ptr->dev == dev &&
+ fsp->fd_ptr->inode == inode &&
+ (tval ? (fsp->open_time.tv_sec == tval->tv_sec) : True ) &&
+ (tval ? (fsp->open_time.tv_usec == tval->tv_usec) : True )) {
+ if (count > 10) {
+ DLIST_PROMOTE(Files, fsp);
+ }
+ return fsp;
+ }
+ }
+#endif
+
+ return NULL;
+}
+
+
+/****************************************************************************
+find a fsp that is open for printing
+****************************************************************************/
+files_struct *file_find_print(void)
+{
+ files_struct *fsp;
+
+#ifdef USE_FILES_ARRAY
+ int i;
+ for(i = 0; i < MAX_FNUMS; i++) {
+ if((fsp = Files[i]) == NULL)
+ continue;
+ if (fsp->open && fsp->print_file) return fsp;
+ }
+#else
+ for (fsp=Files;fsp;fsp=fsp->next) {
+ if (fsp->open && fsp->print_file) return fsp;
+ }
+#endif
+
+ return NULL;
+}
+
+
+/****************************************************************************
+sync open files on a connection
+****************************************************************************/
+void file_sync_all(connection_struct *conn)
+{
+ files_struct *fsp, *next;
+
+#ifdef USE_FILES_ARRAY
+ int i;
+ for(i = 0; i < MAX_FNUMS; i++) {
+ if((fsp = Files[i]) == NULL)
+ continue;
+ if (fsp->open && conn == fsp->conn)
+ sync_file(conn,fsp);
+ }
+#else
+ for (fsp=Files;fsp;fsp=next) {
+ next=fsp->next;
+ if (fsp->open && conn == fsp->conn) {
+ sync_file(conn,fsp);
+ }
+ }
+#endif
+}
+
+
+/****************************************************************************
+free up a fd_ptr
+****************************************************************************/
+void fd_ptr_free(file_fd_struct *fd_ptr)
+{
+ DLIST_REMOVE(FileFd, fd_ptr);
+
+ fd_ptr_used--;
+
+ DEBUG(5,("freed fd_ptr structure (%d used)\n", fd_ptr_used));
+
+ /* paranoia */
+ ZERO_STRUCTP(fd_ptr);
+
+ free(fd_ptr);
+}
+
+
+/****************************************************************************
+free up a fsp
+****************************************************************************/
+void file_free(files_struct *fsp)
+{
+#ifdef USE_FILES_ARRAY
+ files_struct *fsp1 = Files[fsp->fnum - FILE_HANDLE_OFFSET];
+ if(fsp != fsp1)
+ DEBUG(0,("file_free: fnum = %d (array offset %d) <> fsp = %x, fnum = %d!\n",
+ fsp->fnum, fsp->fnum - FILE_HANDLE_OFFSET, fsp1, fsp1->fnum));
+ SMB_ASSERT(fsp == fsp1);
+ Files[fsp->fnum - FILE_HANDLE_OFFSET] = NULL;
+#else
+ DLIST_REMOVE(Files, fsp);
+#endif
+
+ string_free(&fsp->fsp_name);
+
+ if (fsp->fd_ptr && fsp->fd_ptr->ref_count == 0) {
+ fd_ptr_free(fsp->fd_ptr);
+ }
+
+ 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;
+
+ 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);
+
+#ifdef USE_FILES_ARRAY
+ fsp = Files[fnum - FILE_HANDLE_OFFSET];
+ if(!fsp)
+ DEBUG(0,("file_fsp: fnum = %d (array offset %d) gave null fsp !\n",
+ fnum, fnum - FILE_HANDLE_OFFSET));
+ SMB_ASSERT(fsp != NULL);
+
+ return (chain_fsp = fsp);
+#else
+ 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;
+#endif
+}
+
+/****************************************************************************
+ 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..29236e2ca57
--- /dev/null
+++ b/source/smbd/groupname.c
@@ -0,0 +1,243 @@
+/*
+ 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 int DEBUGLEVEL;
+extern DOM_SID global_machine_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) {
+ if(gmep->windows_name)
+ free(gmep->windows_name);
+ if(gmep->unix_name)
+ free(gmep->unix_name);
+ free((char *)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;
+ FILE *fp;
+ char *s;
+ pstring buf;
+ 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.
+ */
+
+ fp = fopen(groupname_map_file,"r");
+ if (!fp) {
+ DEBUG(0,("load_groupname_map: can't open groupname map %s. Error was %s\n",
+ groupname_map_file, strerror(errno)));
+ return;
+ }
+
+ /*
+ * Throw away any previous list.
+ */
+ delete_groupname_map_list();
+
+ DEBUG(4,("load_groupname_map: Scanning groupname map %s\n",groupname_map_file));
+
+ while((s=fgets_slash(buf,sizeof(buf),fp))!=NULL) {
+ pstring unixname;
+ pstring windows_name;
+ struct group *gptr;
+ DOM_SID tmp_sid;
+
+ DEBUG(10,("load_groupname_map: Read line |%s|\n", s));
+
+ if (!*s || strchr("#;",*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((gptr = (struct group *)getgrnam(unixname)) == NULL) {
+ DEBUG(0,("load_groupname_map: getgrnam 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_machine_sid;
+ tmp_sid.sub_auths[tmp_sid.num_auths++] =
+ pdb_gid_to_group_rid((gid_t)gptr->gr_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 = gptr->gr_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);
+ if(new_ep->windows_name != NULL)
+ free(new_ep->windows_name);
+ if(new_ep->unix_name != NULL)
+ free(new_ep->unix_name);
+ free((char *)new_ep);
+ 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)));
+
+ fclose(fp);
+}
+
+/***********************************************************
+ 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_machine_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..ec126c89ff4 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,8 +27,7 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "pcap.h"
+#include "nterr.h"
#ifdef CHECK_TYPES
#undef CHECK_TYPES
@@ -33,11 +35,10 @@
#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;
+extern fstring global_myworkgroup;
#define NERR_Success 0
#define NERR_badpass 86
@@ -48,9 +49,6 @@ extern fstring local_machine;
#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
@@ -62,22 +60,34 @@ extern fstring local_machine;
#define QNLEN 12 /* queue name maximum length */
extern int Client;
+extern int smb_read_error;
-static int CopyExpanded(int cnum, int snum, char** dst, char* src, int* n)
-{
- pstring buf;
- int l;
+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);
- 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 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);
+ string_sub(buf,"%S",lp_servicename(snum));
+ standard_sub(conn,buf);
+ StrnCpy(*dst,buf,*n);
+ l = strlen(*dst) + 1;
+ (*dst) += l;
+ (*n) -= l;
+ return l;
}
static int CopyAndAdvance(char** dst, char* src, int* n)
@@ -91,24 +101,24 @@ static int CopyAndAdvance(char** dst, char* src, int* n)
return l;
}
-static int StrlenExpanded(int cnum, int snum, char* s)
+static int StrlenExpanded(connection_struct *conn, 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;
+ pstring buf;
+ if (!s) return(0);
+ StrnCpy(buf,s,sizeof(buf)/2);
+ string_sub(buf,"%S",lp_servicename(snum));
+ standard_sub(conn,buf);
+ return strlen(buf) + 1;
}
-static char* Expand(int cnum, int snum, char* s)
+static char* Expand(connection_struct *conn, 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];
+ static pstring buf;
+ if (!s) return(NULL);
+ StrnCpy(buf,s,sizeof(buf)/2);
+ string_sub(buf,"%S",lp_servicename(snum));
+ standard_sub(conn,buf);
+ return &buf[0];
}
/*******************************************************************
@@ -119,81 +129,124 @@ 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
+
+ ******************************************************************/
+static void copy_trans_params_and_data(char *outbuf, int align,
+ struct mem_buf *rparam, struct mem_buf *rdata,
+ int param_offset, int data_offset,
+ int param_len, int data_len)
+{
+ char *copy_into = smb_buf(outbuf)+1;
+
+ 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));
+
+ if (param_len) mem_buf_copy(copy_into, rparam, param_offset, param_len);
+ copy_into += param_len + align;
+ if (data_len ) mem_buf_copy(copy_into, rdata , data_offset , data_len);
+}
/****************************************************************************
send a trans reply
****************************************************************************/
-static void send_trans_reply(char *outbuf,char *data,char *param,uint16 *setup,
- int ldata,int lparam,int lsetup)
+static void send_trans_reply(char *outbuf,
+ struct mem_buf *rdata,
+ struct mem_buf *rparam,
+ uint16 *setup, int lsetup, int max_data_ret)
{
- 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;
- }
-}
+ int i;
+ int this_ldata,this_lparam;
+ int tot_data=0,tot_param=0;
+ int align;
+ int ldata = rdata ? mem_buf_len(rdata ) : 0;
+ int lparam = rparam ? mem_buf_len(rparam) : 0;
+ BOOL buffer_too_large = max_data_ret ? ldata > max_data_ret : False;
-/****************************************************************************
- get a print queue
- ****************************************************************************/
+ if (buffer_too_large)
+ {
+ DEBUG(5,("send_trans_reply: buffer %d too large %d\n", ldata, max_data_ret));
+ ldata = max_data_ret;
+ }
+
+ this_lparam = MIN(lparam,max_send - (500+lsetup*SIZEOFWORD)); /* hack */
+ this_ldata = MIN(ldata,max_send - (500+lsetup*SIZEOFWORD+this_lparam));
+
+ align = ((this_lparam)%4);
+
+ set_message(outbuf,10+lsetup,1+align+this_ldata+this_lparam,True);
+
+ if (buffer_too_large)
+ {
+ /* issue a buffer size warning. on a DCE/RPC pipe, expect an SMBreadX... */
+ SIVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ SIVAL(outbuf, smb_rcls, 0x80000000 | NT_STATUS_ACCESS_VIOLATION);
+ }
+
+ copy_trans_params_and_data(outbuf, align,
+ rparam , rdata,
+ tot_param , tot_data,
+ this_lparam, 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,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, max_send - 500); /* hack */
+ this_ldata = MIN(ldata -tot_data , max_send - (500+this_lparam));
+
+ align = (this_lparam%4);
+
+ set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
+
+ copy_trans_params_and_data(outbuf, align,
+ rparam , rdata,
+ tot_param , tot_data,
+ this_lparam, this_ldata);
+
+ SSVAL(outbuf,smb_vwv3,this_lparam);
+ SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
+ SSVAL(outbuf,smb_vwv5,tot_param);
+ 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);
+ SSVAL(outbuf,smb_vwv9,0);
+
+ show_msg(outbuf);
+ send_smb(Client,outbuf);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+}
struct pack_desc {
char* format; /* formatstring for structure */
@@ -214,7 +267,7 @@ static int get_counter(char** p)
{
int i, n;
if (!p || !(*p)) return(1);
- if (!isdigit(**p)) return 1;
+ if (!isdigit((int)**p)) return 1;
for (n = 0;;) {
i = **p;
if (isdigit(i))
@@ -269,11 +322,12 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount)
p->subcount = 0;
p->curpos = p->format;
if (i > n) {
+ p->neededlen = i;
i = n = 0;
- p->errcode = NERR_BufTooSmall;
+ p->errcode = ERRmoredata;
}
-
- p->errcode = NERR_Success;
+ else
+ p->errcode = NERR_Success;
p->buflen = i;
n -= i;
p->stringbuf = p->base + i;
@@ -281,7 +335,7 @@ static BOOL init_package(struct pack_desc* p, int count, int subcount)
return(p->errcode == NERR_Success);
}
-#ifdef __STDC__
+#ifdef HAVE_STDARG_H
static int package(struct pack_desc* p, ...)
{
#else
@@ -296,7 +350,7 @@ va_dcl
int is_string=0, stringused;
int32 temp;
-#ifdef __STDC__
+#ifdef HAVE_STDARG_H
va_start(args,p);
#else
va_start(args);
@@ -313,15 +367,7 @@ va_dcl
}
#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;
- }
+ SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0);
#endif
stringneeded = -1;
@@ -373,7 +419,7 @@ va_dcl
stringused = stringneeded;
if (stringused > p->stringlen) {
stringused = (is_string ? p->stringlen : 0);
- if (p->errcode == NERR_Success) p->errcode = ERROR_MORE_DATA;
+ if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
}
if (!stringused)
SIVAL(p->structbuf,0,0);
@@ -395,7 +441,7 @@ va_dcl
p->usedlen += needed;
}
else {
- if (p->errcode == NERR_Success) p->errcode = NERR_BufTooSmall;
+ if (p->errcode == NERR_Success) p->errcode = ERRmoredata;
}
return 1;
}
@@ -418,18 +464,23 @@ 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 */
- strcpy(drivdata+8,"NULL");
+ pstrcpy(drivdata+8,"NULL");
PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */
}
static int check_printq_info(struct pack_desc* desc,
- int uLevel, const char* id1, const char* id2)
+ int uLevel, char *id1, char *id2)
{
desc->subformat = NULL;
switch( uLevel ) {
@@ -453,6 +504,10 @@ static int check_printq_info(struct pack_desc* desc,
case 5:
desc->format = "z";
break;
+ case 52:
+ desc->format = "WzzzzzzzzN";
+ desc->subformat = "z";
+ break;
default: return False;
}
if (strcmp(desc->format,id1) != 0) return False;
@@ -460,16 +515,16 @@ static int check_printq_info(struct pack_desc* desc,
return True;
}
-static void fill_printjob_info(int cnum, int snum, int uLevel,
+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 += GMT_TO_LOCAL*TimeDiff(t);
+ t -= TimeDiff(t);
- PACKI(desc,"W",((snum%0xFF)<<8) | (queue->job%0xFF)); /* uJobId */
+ PACKI(desc,"W",printjob_encode(snum, queue->job)); /* uJobId */
if (uLevel == 1) {
PACKS(desc,"B21",queue->user); /* szUserName */
PACKS(desc,"B",""); /* pad */
@@ -479,7 +534,7 @@ static void fill_printjob_info(int cnum, int snum, int uLevel,
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",t); /* ulSubmitted */
PACKI(desc,"D",queue->size); /* ulSize */
PACKS(desc,"z",queue->file); /* pszComment */
}
@@ -488,7 +543,7 @@ static void fill_printjob_info(int cnum, int snum, int uLevel,
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",t); /* ulSubmitted */
PACKI(desc,"D",queue->size); /* ulSize */
PACKS(desc,"z","Samba"); /* pszComment */
PACKS(desc,"z",queue->file); /* pszDocument */
@@ -507,16 +562,23 @@ static void fill_printjob_info(int cnum, int snum, int uLevel,
}
}
-static void fill_printq_info(int cnum, int snum, int uLevel,
+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)
{
- if (uLevel < 3) {
- PACKS(desc,"B13",SERVICE(snum));
- } else {
- PACKS(desc,"z",Expand(cnum,snum,SERVICE(snum)));
+ 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;
}
+
if (uLevel == 1 || uLevel == 2) {
PACKS(desc,"B",""); /* alignment */
PACKI(desc,"W",5); /* priority */
@@ -531,7 +593,7 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
PACKI(desc,"W",LPSTAT_ERROR);
}
else if (!status || !status->message[0]) {
- PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum)));
+ PACKS(desc,"z",Expand(conn,snum,lp_comment(snum)));
PACKI(desc,"W",LPSTAT_OK); /* status */
} else {
PACKS(desc,"z",status->message);
@@ -545,10 +607,10 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
PACKI(desc,"W",0); /* uUntiltime */
PACKI(desc,"W",5); /* pad1 */
PACKS(desc,"z",""); /* pszSepFile */
- PACKS(desc,"z","lpd"); /* pszPrProc */
+ PACKS(desc,"z","WinPrint"); /* pszPrProc */
PACKS(desc,"z",""); /* pszParms */
if (!status || !status->message[0]) {
- PACKS(desc,"z",Expand(cnum,snum,lp_comment(snum))); /* pszComment */
+ PACKS(desc,"z",Expand(conn,snum,lp_comment(snum))); /* pszComment */
PACKI(desc,"W",LPSTAT_OK); /* fsStatus */
} else {
PACKS(desc,"z",status->message); /* pszComment */
@@ -556,19 +618,174 @@ static void fill_printq_info(int cnum, int snum, int uLevel,
}
PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */
PACKS(desc,"z",SERVICE(snum)); /* pszPrinters */
- PACKS(desc,"z","NULL"); /* pszDriverName */
+ PACKS(desc,"z",lp_printerdriver(snum)); /* 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);
+ fill_printjob_info(conn,snum,uLevel == 2 ? 1 : 2,desc,&queue[i],i);
}
-
- DEBUG(3,("fill_printq_info on <%s> gave %d entries\n",SERVICE(snum),count));
+
+ if (uLevel==52) {
+ int i,ok=0;
+ pstring tok,driver,datafile,langmon,helpfile,datatype;
+ char *p,*q;
+ FILE *f;
+ pstring fname;
+
+ pstrcpy(fname,lp_driverfile());
+ f=fopen(fname,"r");
+ if (!f) {
+ DEBUG(3,("fill_printq_info: Can't open %s - %s\n",fname,strerror(errno)));
+ desc->errcode=NERR_notsupported;
+ return;
+ }
+
+ if((p=(char *)malloc(8192*sizeof(char))) == NULL) {
+ DEBUG(0,("fill_printq_info: malloc fail !\n"));
+ desc->errcode=NERR_notsupported;
+ fclose(f);
+ return;
+ }
+
+ bzero(p, 8192*sizeof(char));
+ q=p;
+
+ /* lookup the long printer driver name in the file description */
+ while (f && !feof(f) && !ok)
+ {
+ p = q; /* reset string pointer */
+ fgets(p,8191,f);
+ p[strlen(p)-1]='\0';
+ if (next_token(&p,tok,":",sizeof(tok)) &&
+ (strlen(lp_printerdriver(snum)) == strlen(tok)) &&
+ (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
+ ok=1;
+ }
+ fclose(f);
+
+ /* driver file name */
+ if (ok && !next_token(&p,driver,":",sizeof(driver))) ok = 0;
+ /* data file name */
+ if (ok && !next_token(&p,datafile,":",sizeof(datafile))) ok = 0;
+ /*
+ * 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
+ */
+ if (ok) {
+ /* help file */
+ if (*p == ':') {
+ *helpfile = '\0';
+ p++;
+ } else if (!next_token(&p,helpfile,":",sizeof(helpfile))) ok = 0;
+ }
+
+ if (ok) {
+ /* language monitor */
+ if (*p == ':') {
+ *langmon = '\0';
+ p++;
+ } else if (!next_token(&p,langmon,":",sizeof(langmon))) ok = 0;
+ }
+
+ /* default data type */
+ if (ok && !next_token(&p,datatype,":",sizeof(datatype))) ok = 0;
+
+ if (ok) {
+ PACKI(desc,"W",0x0400); /* don't know */
+ PACKS(desc,"z",lp_printerdriver(snum)); /* long printer name */
+ PACKS(desc,"z",driver); /* Driverfile Name */
+ PACKS(desc,"z",datafile); /* Datafile name */
+ PACKS(desc,"z",langmon); /* language monitor */
+ 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,("Driver:%s:\n",driver));
+ DEBUG(3,("Data File:%s:\n",datafile));
+ DEBUG(3,("Language Monitor:%s:\n",langmon));
+ 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));
+ } else {
+ DEBUG(3,("fill_printq_info: Can't supply driver files\n"));
+ desc->errcode=NERR_notsupported;
+ }
+ free(q);
+ }
+}
+
+/* This function returns the number of files for a given driver */
+static int get_printerdrivernumber(int snum)
+{
+ int i=0,ok=0;
+ pstring tok;
+ char *p,*q;
+ FILE *f;
+ pstring fname;
+
+ pstrcpy(fname,lp_driverfile());
+
+ DEBUG(4,("In get_printerdrivernumber: %s\n",fname));
+ f=fopen(fname,"r");
+ if (!f) {
+ DEBUG(3,("get_printerdrivernumber: Can't open %s - %s\n",fname,strerror(errno)));
+ return(0);
+ }
+
+ if((p=(char *)malloc(8192*sizeof(char))) == NULL) {
+ DEBUG(3,("get_printerdrivernumber: malloc fail !\n"));
+ fclose(f);
+ return 0;
+ }
+
+ q=p; /* need it to free memory because p change ! */
+
+ /* lookup the long printer driver name in the file description */
+ while (!feof(f) && !ok)
+ {
+ p = q; /* reset string pointer */
+ fgets(p,8191,f);
+ if (next_token(&p,tok,":",sizeof(tok)) &&
+ (!strncmp(tok,lp_printerdriver(snum),strlen(lp_printerdriver(snum)))))
+ ok=1;
+ }
+ fclose(f);
+
+ if (ok) {
+ /* skip 5 fields */
+ i = 5;
+ while (*p && i) {
+ if (*p++ == ':') i--;
+ }
+ if (!*p || i)
+ return(0);
+
+ /* count the number of files */
+ while (next_token(&p,tok,",",sizeof(tok)))
+ i++;
+ }
+ free(q);
+
+ return(i);
}
-static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
+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)
@@ -577,7 +794,7 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
char *QueueName = p;
- int uLevel,cbBuf;
+ int uLevel;
int count=0;
int snum;
char* str3;
@@ -590,9 +807,9 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
p = skip_string(p,1);
uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
str3 = p + 4;
+ /* remove any trailing username */
if ((p = strchr(QueueName,'%'))) *p = 0;
DEBUG(3,("PrintQueue uLevel=%d name=%s\n",uLevel,QueueName));
@@ -612,13 +829,19 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
if (snum < 0 || !VALID_SNUM(snum)) return(False);
- count = get_printqueue(snum,cnum,&queue,&status);
+ if (uLevel==52) {
+ count = get_printerdrivernumber(snum);
+ DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count));
+ } else {
+ count = get_printqueue(snum, conn,&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);
+ desc.subcount = count;
+ fill_printq_info(conn,snum,uLevel,&desc,count,queue,&status);
}
*rdata_len = desc.usedlen;
@@ -640,7 +863,7 @@ static BOOL api_DosPrintQGetInfo(int cnum,int uid, char *param,char *data,
/****************************************************************************
view list of all print jobs on all queues
****************************************************************************/
-static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
+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)
@@ -662,7 +885,7 @@ static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel));
- if (prefix_ok(param_format,"WrLeh")) return False;
+ if (!prefix_ok(param_format,"WrLeh")) return False;
if (!check_printq_info(&desc,uLevel,output_format1,output_format2))
return False;
queuecnt = 0;
@@ -670,16 +893,25 @@ static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
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*));
+ 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*));
- status = (print_status_struct*)malloc(queuecnt*sizeof(print_status_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));
- subcntarr = (int*)malloc(queuecnt*sizeof(int));
+ 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] = get_printqueue(i,cnum,&queue[n],&status[n]);
+ subcntarr[n] = get_printqueue(i, conn,&queue[n],&status[n]);
subcnt += subcntarr[n];
n++;
}
@@ -693,7 +925,7 @@ static BOOL api_DosPrintQEnum(int cnum, int uid, char* param, char* data,
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]);
+ fill_printq_info(conn,i,uLevel,&desc,subcntarr[n],queue[n],&status[n]);
n++;
if (desc.errcode == NERR_Success) succnt = n;
}
@@ -737,69 +969,35 @@ static BOOL check_server_info(int uLevel, char* id)
return True;
}
-/* 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 */
+ fstring domain;
+ BOOL server_added;
};
-/*******************************************************************
- 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! */
-}
-
-/*******************************************************************
- 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;
-
- if (!servers || num_servers == 0) return (False);
-
- for (count = 0; count < num_servers; count++) {
- struct srv_info_struct *s;
-
- s = &servers[count];
-
- if (strequal(name, s->name)) {
- StrnCpy(domain, s->domain, sizeof(pstring)-1);
- return (True);
- }
- }
- return (False);
-}
-
/*******************************************************************
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)
+ struct srv_info_struct **servers,
+ char *domain)
{
FILE *f;
pstring fname;
int count=0;
int alloced=0;
pstring line;
+ BOOL local_list_only;
- strcpy(fname,lp_lockdir());
+ pstrcpy(fname,lp_lockdir());
trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
+ pstrcat(fname,"/");
+ pstrcat(fname,SERVER_LIST);
f = fopen(fname,"r");
@@ -807,18 +1005,26 @@ static int get_server_info(uint32 servertype,
DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno)));
return(0);
}
- if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM;
+
+ /* 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));
while (!feof(f))
{
fstring stype;
struct srv_info_struct *s;
char *ptr = line;
+ BOOL ok = True;
*ptr = 0;
fgets(line,sizeof(line)-1,f);
if (!*line) continue;
-
+
if (count == alloced) {
alloced += 10;
(*servers) = (struct srv_info_struct *)
@@ -827,36 +1033,69 @@ static int get_server_info(uint32 servertype,
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 (!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. */
- if (sscanf(stype,"%X",&s->type) != 1) continue;
+ /* 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)) 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));
+ 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;
- count++;
+ 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));
+ }
}
-
+
fclose(f);
return(count);
}
+
/*******************************************************************
fill in a server info structure
******************************************************************/
@@ -936,11 +1175,16 @@ static int fill_srv_info(struct srv_info_struct *service,
}
+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(int cnum, int uid, char *param, char *data,
+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)
{
@@ -952,63 +1196,77 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
uint32 servertype = IVAL(p,4);
char *p2;
int data_len, fixed_len, string_len;
- int f_len, s_len;
+ int f_len = 0, s_len = 0;
struct srv_info_struct *servers=NULL;
int counted=0,total=0;
- int i;
+ int i,missed;
fstring domain;
- BOOL domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) &&
- !(servertype == SV_TYPE_ALL);
+ 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);
- 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));
+ 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, "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 */
+ if (strcmp(str1, "WrLehDz") == 0) {
StrnCpy(domain, p, sizeof(fstring)-1);
+ } else {
+ StrnCpy(domain, global_myworkgroup, 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());
- }
- }
+ total = get_server_info(servertype,&servers,domain);
data_len = fixed_len = string_len = 0;
+ missed = 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)
- {
+ 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);
@@ -1020,30 +1278,68 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
s_len = string_len;
{
+ char *lastname=NULL;
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);
+ 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,NERR_Success);
+ SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata));
SSVAL(*rparam,2,0);
SSVAL(*rparam,4,counted);
- SSVAL(*rparam,6,total);
+ SSVAL(*rparam,6,counted+missed);
if (servers) free(servers);
DEBUG(3,("NetServerEnum domain = %s uLevel=%d counted=%d total=%d\n",
- domain,uLevel,counted,total));
+ 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;
+ *rdata = NULL;
+
+ *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
@@ -1068,7 +1364,7 @@ static BOOL check_share_info(int uLevel, char* id)
return True;
}
-static int fill_share_info(int cnum, int snum, int uLevel,
+static int fill_share_info(connection_struct *conn, int snum, int uLevel,
char** buf, int* buflen,
char** stringbuf, int* stringspace, char* baseaddr)
{
@@ -1090,7 +1386,7 @@ static int fill_share_info(int cnum, int snum, int uLevel,
if (!buf)
{
len = 0;
- if (uLevel > 0) len += StrlenExpanded(cnum,snum,lp_comment(snum));
+ 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;
@@ -1123,7 +1419,7 @@ static int fill_share_info(int cnum, int snum, int uLevel,
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);
+ len += CopyExpanded(conn,snum,&p2,lp_comment(snum),&l2);
}
if (uLevel > 1)
@@ -1163,7 +1459,7 @@ static int fill_share_info(int cnum, int snum, int uLevel,
return len;
}
-static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
+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)
@@ -1183,7 +1479,7 @@ static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
*rdata = REALLOC(*rdata,mdrcnt);
p = *rdata;
- *rdata_len = fill_share_info(cnum,snum,uLevel,&p,&mdrcnt,0,0,0);
+ *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0);
if (*rdata_len < 0) return False;
*rparam_len = 6;
@@ -1198,7 +1494,7 @@ static BOOL api_RNetShareGetInfo(int cnum,int uid, char *param,char *data,
/****************************************************************************
view list of shares available
****************************************************************************/
-static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
+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)
@@ -1211,9 +1507,10 @@ static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
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, s_len;
+ int f_len = 0, s_len = 0;
if (!prefix_ok(str1,"WrLeh")) return False;
if (!check_share_info(uLevel,str2)) return False;
@@ -1221,16 +1518,18 @@ static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
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)
{
- 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;
- }
+ 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);
@@ -1241,12 +1540,12 @@ static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
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)
+ 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,NERR_Success);
+ SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success);
SSVAL(*rparam,2,0);
SSVAL(*rparam,4,counted);
SSVAL(*rparam,6,total);
@@ -1262,7 +1561,7 @@ static BOOL api_RNetShareEnum(int cnum,int uid, char *param,char *data,
/****************************************************************************
get the time of day info
****************************************************************************/
-static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
+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)
@@ -1289,7 +1588,7 @@ static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
/* the client expects to get localtime, not GMT, in this bit
(I think, this needs testing) */
- t = LocalTime(&unixdate,GMT_TO_LOCAL);
+ t = LocalTime(&unixdate);
SIVAL(p,4,0); /* msecs ? */
CVAL(p,8) = t->tm_hour;
@@ -1311,7 +1610,7 @@ static BOOL api_NetRemoteTOD(int cnum,int uid, char *param,char *data,
/****************************************************************************
set the user password
****************************************************************************/
-static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
+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)
@@ -1320,26 +1619,62 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
fstring user;
fstring pass1,pass2;
- strcpy(user,p);
+ fstrcpy(user,p);
p = skip_string(p,1);
- StrnCpy(pass1,p,16);
- StrnCpy(pass2,p+16,16);
+ memcpy(pass1,p,16);
+ memcpy(pass2,p+16,16);
*rparam_len = 4;
*rparam = REALLOC(*rparam,*rparam_len);
*rdata_len = 0;
- SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,0,NERR_badpass);
SSVAL(*rparam,2,0); /* converter word */
DEBUG(3,("Set password for <%s>\n",user));
- if (!password_ok(user,pass1,strlen(pass1),NULL,False) ||
- !chgpasswd(user,pass1,pass2))
- SSVAL(*rparam,0,NERR_badpass);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam( user, True);
+
+ /*
+ * Attempt the plaintext password change first.
+ * Older versions of Windows seem to do this.
+ */
+
+ if (password_ok(user,pass1,strlen(pass1),NULL) &&
+ chgpasswd(user,pass1,pass2,False))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+
+ /*
+ * If the plaintext change failed, attempt
+ * the encrypted. NT will generate this
+ * after trying the samr method.
+ */
+
+ if(SVAL(*rparam,0) != NERR_Success)
+ {
+ struct smb_passwd *sampw = NULL;
+
+ if(check_lanman_password(user,(unsigned char *)pass1,(unsigned char *)pass2, &sampw) &&
+ change_lanman_password(sampw,(unsigned char *)pass1,(unsigned char *)pass2))
+ {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+ }
bzero(pass1,sizeof(fstring));
bzero(pass2,sizeof(fstring));
@@ -1348,10 +1683,88 @@ static BOOL api_SetUserPassword(int cnum,int uid, char *param,char *data,
}
/****************************************************************************
+ 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;
+ fstring new_passwd;
+ struct smb_passwd *sampw = NULL;
+ char *p = param + 2;
+ int ret = True;
+
+ *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 %sn\n", param + 2));
+ return False;
+ }
+ p = skip_string(p, 1);
+
+ if(!strequal(p, "B516B16")) {
+ DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %sn\n", p));
+ return False;
+ }
+ p = skip_string(p,1);
+
+ fstrcpy(user,p);
+ p = skip_string(p,1);
+
+ 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( user, True);
+
+ if(check_oem_password( user, (unsigned char *)data, &sampw,
+ new_passwd, (int)sizeof(new_passwd)) == False) {
+ return True;
+ }
+
+ /*
+ * 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(lp_unix_password_sync())
+ ret = chgpasswd(user,"", new_passwd, True);
+
+ if(ret && change_oem_password( sampw, new_passwd, False)) {
+ SSVAL(*rparam,0,NERR_Success);
+ }
+
+ return(True);
+}
+
+/****************************************************************************
delete a print job
Form: <W> <>
****************************************************************************/
-static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
+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)
@@ -1360,11 +1773,10 @@ static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
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 jobid, snum;
int i, count;
+ printjob_decode(SVAL(p,0), &snum, &jobid);
/* check it's a supported varient */
if (!(strcsequal(str1,"W") && strcsequal(str2,"")))
@@ -1381,21 +1793,21 @@ static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
{
print_queue_struct *queue=NULL;
lpq_reset(snum);
- count = get_printqueue(snum,cnum,&queue,NULL);
+ count = get_printqueue(snum,conn,&queue,NULL);
for (i=0;i<count;i++)
- if ((queue[i].job%0xFF) == jobid)
+ 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);
+ del_printqueue(conn,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,
+ status_printjob(conn,snum,queue[i].job,
(function==82?LPQ_PAUSED:LPQ_QUEUED));
break;
}
@@ -1413,11 +1825,15 @@ static BOOL api_RDosPrintJobDel(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintQueuePurge(int cnum,int uid, char *param,char *data,
+/****************************************************************************
+ Purge a print queue - or pause or resume it.
+ ****************************************************************************/
+static BOOL api_WPrintQueuePurge(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);
@@ -1445,19 +1861,30 @@ static BOOL api_WPrintQueuePurge(int cnum,int uid, char *param,char *data,
}
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);
+ switch (function) {
+ case 74: /* Pause queue */
+ case 75: /* Resume queue */
+ status_printqueue(conn,snum,(function==74?LPSTAT_STOPPED:LPSTAT_OK));
+ DEBUG(3,("Print queue %s, queue=%s\n",
+ (function==74?"pause":"resume"),QueueName));
+ break;
+ case 103: /* Purge */
+ {
+ print_queue_struct *queue=NULL;
+ int i, count;
+ count = get_printqueue(snum,conn,&queue,NULL);
+ for (i = 0; i < count; i++)
+ del_printqueue(conn,snum,queue[i].job);
+
+ if (queue) free(queue);
+ DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
+ break;
+ }
+ }
}
- DEBUG(3,("Print queue purge, queue=%s\n",QueueName));
-
return(True);
}
@@ -1484,115 +1911,117 @@ static int check_printjob_info(struct pack_desc* desc,
return True;
}
-static BOOL api_PrintJobInfo(int cnum,int uid,char *param,char *data,
+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 = (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;
+ struct pack_desc desc;
+ char *str1 = param+2;
+ char *str2 = skip_string(str1,1);
+ char *p = skip_string(str2,1);
+ int jobid, snum;
+ int uLevel = SVAL(p,2);
+ int function = SVAL(p,4); /* what is this ?? */
+ int i;
+ char *s = data;
+ files_struct *fsp;
+
+ printjob_decode(SVAL(p,0), &snum, &jobid);
- *rparam_len = 4;
- *rparam = REALLOC(*rparam,*rparam_len);
-
- *rdata_len = 0;
+ *rparam_len = 4;
+ *rparam = REALLOC(*rparam,*rparam_len);
- /* check it's a supported varient */
- if ((strcmp(str1,"WWsTP")) || (!check_printjob_info(&desc,uLevel,str2)))
- return(False);
+ *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;
+ 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;
+ lpq_reset(snum);
+ count = get_printqueue(snum,conn,&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);
- }
- else {
- desc.errcode=NERR_Success;
- i++;
+ if (i==count) {
+ desc.errcode=NERR_JobNotFound;
+ if (queue) free(queue);
+ } 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 */;
- }
+ {
+ 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;
+ 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((int)*s)) {
+ pstring name;
+ int l = 0;
+ while (l<64 && *s) {
+ if (issafe(*s)) name[l++] = *s;
+ s++;
+ }
+ name[l] = 0;
- DEBUG(3,("Setting print name to %s\n",name));
+ 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();
+ fsp = file_find_print();
+
+ if (fsp) {
+ connection_struct *fconn = fsp->conn;
+ unbecome_user();
- if (!become_user(Files[i].cnum,uid) ||
- !become_service(Files[i].cnum,True))
- break;
+ if (!become_user(fconn,vuid) ||
+ !become_service(fconn,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;
- }
+ if (dos_rename(fsp->fsp_name,name) == 0) {
+ string_set(&fsp->fsp_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);
+ SSVALS(*rparam,0,desc.errcode);
+ SSVAL(*rparam,2,0); /* converter word */
+
+ return(True);
}
/****************************************************************************
get info about the server
****************************************************************************/
-static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
+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)
@@ -1653,28 +2082,29 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
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;
+ uint32 servertype= lp_default_server_announce();
- strcpy(comment,lp_serverstring());
+ pstrcpy(comment,lp_serverstring());
- if ((count=get_server_info(SV_TYPE_ALL,&servers))>0) {
+ 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)) {
+ if (strequal(servers[i].name,local_machine))
+ {
servertype = servers[i].type;
- strcpy(comment,servers[i].comment);
+ pstrcpy(comment,servers[i].comment);
}
}
if (servers) free(servers);
- SCVAL(p,0,2); /* version_major */
- SCVAL(p,1,0); /* version_minor */
+ 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(cnum,comment);
+ standard_sub(conn,comment);
StrnCpy(p2,comment,MAX(mdrcnt - struct_len,0));
p2 = skip_string(p2,1);
}
@@ -1699,7 +2129,7 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data,
/****************************************************************************
get info about the server
****************************************************************************/
-static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
+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)
@@ -1729,32 +2159,35 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
p = *rdata;
p2 = p + 22;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,local_machine);
+
+ 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));
- strcpy(p2,sesssetup_user);
+ pstrcpy(p2,sesssetup_user);
p2 = skip_string(p2,1);
p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,my_workgroup());
+ 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,2); /* major version?? */
- SCVAL(p,1,1); /* minor version?? */
+ 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));
- strcpy(p2,my_workgroup()); /* login domain?? */
+ pstrcpy(p2,global_myworkgroup); /* don't know. login domain?? */
p2 = skip_string(p2,1);
p += 4;
- SIVAL(p,0,PTR_DIFF(p2,*rdata));
- strcpy(p2,"");
+ SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */
+ pstrcpy(p2,"");
p2 = skip_string(p2,1);
p += 4;
@@ -1765,154 +2198,334 @@ static BOOL api_NetWkstaGetInfo(int cnum,int uid, char *param,char *data,
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
-static BOOL api_RNetUserGetInfo(int cnum,int uid, char *param,char *data,
+#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;
+ 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", vuser->uid, vuser->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;
+ }
- *rparam_len = 6;
- *rparam = REALLOC(*rparam,*rparam_len);
+ if (strcmp(p2,str2) != 0) return False;
- /* 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);
- *rdata_len = mdrcnt + 1024;
- *rdata = REALLOC(*rdata,*rdata_len);
+ SSVAL(*rparam,0,NERR_Success);
+ SSVAL(*rparam,2,0); /* converter word */
- SSVAL(*rparam,0,NERR_Success);
- SSVAL(*rparam,2,0); /* converter word */
+ p = *rdata;
+ p2 = p + usri11_end;
- p = *rdata;
- p2 = p + 86;
+ memset(p,0,21);
+ fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */
- 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 */
- }
- }
- }
+ 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->real_name : UserName));
+ p2 = skip_string(p2,1);
+ }
- *rdata_len = PTR_DIFF(p2,*rdata);
+ 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_path());
+ 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_path());
+ 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 */
+ pstrcpy(p2,((vuser != NULL) ? vuser->real_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_basic(p2);
+ p2 = skip_string(p2,1);
+ SSVAL(p,110,49); /* country_code */
+ SSVAL(p,112,860); /* code page */
+ }
+ }
- SSVAL(*rparam,4,*rdata_len); /* is this right?? */
+ *rdata_len = PTR_DIFF(p2,*rdata);
- return(True);
-}
+ 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,
+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)
@@ -1945,10 +2558,10 @@ static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
p = *rdata;
/* 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++;
+ 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);
@@ -1959,7 +2572,7 @@ static BOOL api_NetUserGetGroups(int cnum,int uid, char *param,char *data,
}
-static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
+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)
@@ -1970,6 +2583,7 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
int uLevel;
struct pack_desc desc;
char* name;
+ char* logon_script;
uLevel = SVAL(p,0);
name = p + 2;
@@ -1987,18 +2601,17 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
desc.subformat = NULL;
desc.format = str2;
-
-
- if (init_package(&desc,1,0)) {
+ 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);
+ 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",-1); /* last logon */
+ PACKI(&desc,"D",0); /* last logon */
PACKI(&desc,"D",-1); /* last logoff */
PACKI(&desc,"D",-1); /* logoff time */
PACKI(&desc,"D",-1); /* kickoff time */
@@ -2007,14 +2620,21 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
PACKI(&desc,"D",-1); /* password must change */
{
fstring mypath;
- strcpy(mypath,"\\\\");
- strcat(mypath,local_machine);
+ fstrcpy(mypath,"\\\\");
+ fstrcat(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 */
+ 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 */
+ logon_script = lp_logon_script();
+ standard_sub( conn, logon_script );
+ PACKS(&desc,"z", logon_script); /* script path */
+/* End of JHT mods */
+
+ PACKI(&desc,"D",0x00000000); /* reserved */
}
*rdata_len = desc.usedlen;
@@ -2032,7 +2652,7 @@ static BOOL api_WWkstaUserLogon(int cnum,int uid, char *param,char *data,
/****************************************************************************
api_WAccessGetUserPerms
****************************************************************************/
-static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
+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)
@@ -2060,7 +2680,7 @@ static BOOL api_WAccessGetUserPerms(int cnum,int uid, char *param,char *data,
/****************************************************************************
api_WPrintJobEnumerate
****************************************************************************/
-static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
+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)
@@ -2068,8 +2688,7 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
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 uLevel;
int count;
int i;
int snum;
@@ -2079,25 +2698,23 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
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));
+ 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;
- snum = (unsigned int)uJobId >> 8; /*## valid serice number??*/
- job = uJobId & 0xFF;
+ printjob_decode(SVAL(p,0), &snum, &job);
if (snum < 0 || !VALID_SNUM(snum)) return(False);
- count = get_printqueue(snum,cnum,&queue,&status);
+ count = get_printqueue(snum,conn,&queue,&status);
for (i = 0; i < count; i++) {
- if ((queue[i].job % 0xFF) == job) break;
+ if ((queue[i].job & 0xFF) == job) break;
}
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
desc.base = *rdata;
@@ -2105,7 +2722,7 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
if (init_package(&desc,1,0)) {
if (i < count) {
- fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
+ fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
*rdata_len = desc.usedlen;
}
else {
@@ -2126,7 +2743,7 @@ static BOOL api_WPrintJobGetInfo(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
+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)
@@ -2135,7 +2752,7 @@ static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
char* name = p;
- int uLevel,cbBuf;
+ int uLevel;
int count;
int i, succnt=0;
int snum;
@@ -2148,7 +2765,6 @@ static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
p = skip_string(p,1);
uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name));
@@ -2168,7 +2784,7 @@ static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
if (snum < 0 || !VALID_SNUM(snum)) return(False);
- count = get_printqueue(snum,cnum,&queue,&status);
+ count = get_printqueue(snum,conn,&queue,&status);
if (mdrcnt > 0) *rdata = REALLOC(*rdata,mdrcnt);
desc.base = *rdata;
desc.buflen = mdrcnt;
@@ -2176,7 +2792,7 @@ static BOOL api_WPrintJobEnumerate(int cnum,int uid, char *param,char *data,
if (init_package(&desc,count,0)) {
succnt = 0;
for (i = 0; i < count; i++) {
- fill_printjob_info(cnum,snum,uLevel,&desc,&queue[i],i);
+ fill_printjob_info(conn,snum,uLevel,&desc,&queue[i],i);
if (desc.errcode == NERR_Success) succnt = i+1;
}
}
@@ -2211,11 +2827,12 @@ static int check_printdest_info(struct pack_desc* desc,
return True;
}
-static void fill_printdest_info(int cnum, int snum, int uLevel,
+static void fill_printdest_info(connection_struct *conn, int snum, int uLevel,
struct pack_desc* desc)
{
char buf[100];
- strcpy(buf,SERVICE(snum));
+ strncpy(buf,SERVICE(snum),sizeof(buf)-1);
+ buf[sizeof(buf)-1] = 0;
strupper(buf);
if (uLevel <= 1) {
PACKS(desc,"B9",buf); /* szName */
@@ -2243,7 +2860,7 @@ static void fill_printdest_info(int cnum, int snum, int uLevel,
}
}
-static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
+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)
@@ -2252,7 +2869,7 @@ static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
char* PrinterName = p;
- int uLevel,cbBuf;
+ int uLevel;
struct pack_desc desc;
int snum;
@@ -2260,7 +2877,6 @@ static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
p = skip_string(p,1);
uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName));
@@ -2287,7 +2903,7 @@ static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
desc.base = *rdata;
desc.buflen = mdrcnt;
if (init_package(&desc,1,0)) {
- fill_printdest_info(cnum,snum,uLevel,&desc);
+ fill_printdest_info(conn,snum,uLevel,&desc);
}
*rdata_len = desc.usedlen;
}
@@ -2302,7 +2918,7 @@ static BOOL api_WPrintDestGetInfo(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
+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)
@@ -2310,7 +2926,7 @@ static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int uLevel,cbBuf;
+ int uLevel;
int queuecnt;
int i, n, succnt=0;
struct pack_desc desc;
@@ -2319,7 +2935,6 @@ static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
bzero(&desc,sizeof(desc));
uLevel = SVAL(p,0);
- cbBuf = SVAL(p,2);
DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel));
@@ -2340,7 +2955,7 @@ static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
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);
+ fill_printdest_info(conn,i,uLevel,&desc);
n++;
if (desc.errcode == NERR_Success) succnt = n;
}
@@ -2360,7 +2975,7 @@ static BOOL api_WPrintDestEnum(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
+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)
@@ -2368,14 +2983,13 @@ static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int uLevel,cbBuf;
+ int uLevel;
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));
@@ -2405,7 +3019,7 @@ static BOOL api_WPrintDriverEnum(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
+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)
@@ -2413,14 +3027,13 @@ static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int uLevel,cbBuf;
+ int uLevel;
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));
@@ -2451,7 +3064,7 @@ static BOOL api_WPrintQProcEnum(int cnum,int uid, char *param,char *data,
return(True);
}
-static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
+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)
@@ -2459,14 +3072,13 @@ static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
char *str1 = param+2;
char *str2 = skip_string(str1,1);
char *p = skip_string(str2,1);
- int uLevel,cbBuf;
+ int uLevel;
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));
@@ -2498,10 +3110,337 @@ static BOOL api_WPrintPortEnum(int cnum,int uid, char *param,char *data,
return(True);
}
+struct api_cmd
+{
+ char * pipe_clnt_name;
+ char * pipe_srv_name;
+ BOOL (*fn) (pipes_struct *, prs_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 },
+ { NULL, NULL, NULL }
+};
+
+static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd)
+{
+ BOOL ntlmssp_auth = False;
+ fstring ack_pipe_name;
+ int i = 0;
+
+ DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__));
+
+ 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) return False;
+
+ /* decode the bind request */
+ smb_io_rpc_hdr_rb("", &p->hdr_rb, pd, 0);
+
+ if (pd->offset == 0) return False;
+
+ if (p->hdr.auth_len != 0)
+ {
+ /* decode the authentication verifier */
+ smb_io_rpc_auth_ntlmssp_req("", &p->ntlmssp_req, pd, 0);
+
+ if (pd->offset == 0) return False;
+
+ /* ignore the version number for now */
+ ntlmssp_auth = strequal(p->ntlmssp_req.ntlmssp_str, "NTLMSSP");
+ }
+
+ /* name has to be \PIPE\xxxxx */
+ fstrcpy(ack_pipe_name, "\\PIPE\\");
+ fstrcat(ack_pipe_name, p->pipe_srv_name);
+
+ DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__));
+
+ prs_init(&(p->rdata), 1024, 4, 0, False);
+ prs_init(&(p->rhdr ), 0x10, 4, 0, False);
+ prs_init(&(p->rauth), 1024, 4, 0, False);
+
+ /***/
+ /*** do the bind ack first ***/
+ /***/
+
+ make_rpc_hdr_ba(&p->hdr_ba,
+ p->hdr_rb.bba.max_tsize,
+ p->hdr_rb.bba.max_rsize,
+ p->hdr_rb.bba.assoc_gid,
+ ack_pipe_name,
+ 0x1, 0x0, 0x0,
+ &(p->hdr_rb.transfer));
+
+ smb_io_rpc_hdr_ba("", &p->hdr_ba, &p->rdata, 0);
+ mem_realloc_data(p->rdata.data, p->rdata.offset);
+
+ /***/
+ /*** now the authentication ***/
+ /***/
+
+ if (ntlmssp_auth)
+ {
+ uint8 data[16];
+ bzero(data, sizeof(data)); /* first 8 bytes are non-zero */
+
+ make_rpc_auth_ntlmssp_resp(&p->ntlmssp_resp,
+ 0x0a, 0x06, 0,
+ "NTLMSSP", 2,
+ 0x00000000, 0x0000b2b3, 0x000082b1,
+ data);
+ smb_io_rpc_auth_ntlmssp_resp("", &p->ntlmssp_resp, &p->rauth, 0);
+ mem_realloc_data(p->rauth.data, p->rauth.offset);
+ }
+
+ /***/
+ /*** then do the header, now we know the length ***/
+ /***/
+
+ make_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST,
+ p->hdr.call_id,
+ p->rdata.offset + p->rauth.offset + 0x10,
+ p->rauth.offset);
+
+ smb_io_rpc_hdr("", &p->hdr, &p->rhdr, 0);
+ mem_realloc_data(p->rhdr.data, p->rdata.offset);
+
+ /***/
+ /*** link rpc header, bind acknowledgment and authentication responses ***/
+ /***/
+
+ p->rhdr.data->offset.start = 0;
+ p->rhdr.data->offset.end = p->rhdr.offset;
+ p->rhdr.data->next = p->rdata.data;
+
+ if (ntlmssp_auth)
+ {
+ p->rdata.data->offset.start = p->rhdr.offset;
+ p->rdata.data->offset.end = p->rhdr.offset + p->rdata.offset;
+ p->rdata.data->next = p->rauth.data;
+
+ p->rauth.data->offset.start = p->rhdr.offset + p->rdata.offset;
+ p->rauth.data->offset.end = p->rhdr.offset + p->rauth.offset + p->rdata.offset;
+ p->rauth.data->next = NULL;
+ }
+ else
+ {
+ p->rdata.data->offset.start = p->rhdr.offset;
+ p->rdata.data->offset.end = p->rhdr.offset + p->rdata.offset;
+ p->rdata.data->next = NULL;
+ }
+
+ return True;
+}
+
+static BOOL api_pipe_request(pipes_struct *p, prs_struct *pd)
+{
+ int i = 0;
+
+ 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));
+ return api_fd_commands[i].fn(p, pd);
+ }
+ }
+ return False;
+}
+
+static BOOL api_dce_rpc_command(char *outbuf,
+ pipes_struct *p,
+ prs_struct *pd)
+{
+ BOOL reply = False;
+ if (pd->data == NULL) return False;
+
+ /* process the rpc header */
+ smb_io_rpc_hdr("", &p->hdr, pd, 0);
+
+ if (pd->offset == 0) return False;
+
+ switch (p->hdr.pkt_type)
+ {
+ case RPC_BIND :
+ {
+ reply = api_pipe_bind_req(p, pd);
+ break;
+ }
+ case RPC_REQUEST:
+ {
+ reply = api_pipe_request (p, pd);
+ break;
+ }
+ }
+
+ if (reply)
+ {
+ /* now send the reply */
+ send_trans_reply(outbuf, p->rhdr.data, NULL, NULL, 0, p->file_offset);
+
+ if (mem_buf_len(p->rhdr.data) <= p->file_offset)
+ {
+ /* all of data was sent: no need to wait for SMBreadX calls */
+ mem_free_data(p->rhdr .data);
+ mem_free_data(p->rdata.data);
+ }
+ }
+
+ return reply;
+}
+
+/****************************************************************************
+ SetNamedPipeHandleState
+****************************************************************************/
+static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param)
+{
+ uint16 id;
+
+ if (!param) return False;
+
+ id = param[0] + (param[1] << 8);
+ DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n", id));
+
+ if (set_rpc_pipe_hnd_state(p, id))
+ {
+ /* now send the reply */
+ send_trans_reply(outbuf, NULL, NULL, NULL, 0, p->file_offset);
+
+ return True;
+ }
+ return False;
+}
+
+
+/****************************************************************************
+ when no reply is generated, indicate unsupported.
+ ****************************************************************************/
+static BOOL api_no_reply(char *outbuf, int max_rdata_len)
+{
+ struct mem_buf rparam;
+
+ mem_init(&rparam, 0);
+ mem_alloc_data(&rparam, 4);
+
+ rparam.offset.start = 0;
+ rparam.offset.end = 4;
+
+ /* unsupported */
+ SSVAL(rparam.data,0,NERR_notsupported);
+ SSVAL(rparam.data,2,0); /* converter word */
+
+ DEBUG(3,("Unsupported API fd command\n"));
+
+ /* now send the reply */
+ send_trans_reply(outbuf, NULL, &rparam, NULL, 0, max_rdata_len);
+
+ mem_free_data(&rparam);
+
+ return(-1);
+}
+
+/****************************************************************************
+ handle remote api calls delivered to a named pipe already opened.
+ ****************************************************************************/
+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)
+{
+ BOOL reply = False;
+
+ int pnum;
+ int subcommand;
+ pipes_struct *p = NULL;
+ prs_struct pd;
+ struct mem_buf data_buf;
+
+ DEBUG(5,("api_fd_reply\n"));
+
+ /* fake up a data buffer from the api_fd_reply data parameters */
+ mem_create(&data_buf, data, tdscnt, 0, False);
+ data_buf.offset.start = 0;
+ data_buf.offset.end = tdscnt;
+
+ /* fake up a parsing structure */
+ pd.data = &data_buf;
+ pd.align = 4;
+ pd.io = True;
+ pd.offset = 0;
+
+ /* First find out the name of this file. */
+ if (suwcnt != 2)
+ {
+ DEBUG(0,("Unexpected named pipe transaction.\n"));
+ return(-1);
+ }
+
+ /* Get the file handle and hence the file name. */
+ pnum = setup[1];
+ subcommand = setup[0];
+ p = get_rpc_pipe(pnum);
+
+ if (p != NULL)
+ {
+ DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)",
+ subcommand, p->name, pnum));
+
+ /* record maximum data length that can be transmitted in an SMBtrans */
+ p->file_offset = mdrcnt;
+
+ DEBUG(10,("api_fd_reply: p:%p file_offset: %d\n",
+ p, p->file_offset));
+
+ switch (subcommand)
+ {
+ case 0x26:
+ {
+ /* dce/rpc command */
+ reply = api_dce_rpc_command(outbuf, p, &pd);
+ break;
+ }
+ case 0x01:
+ {
+ /* Set Named Pipe Handle state */
+ reply = api_SNPHS(outbuf, p, params);
+ break;
+ }
+ }
+ }
+ else
+ {
+ DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
+ }
+
+ if (!reply)
+ {
+ return api_no_reply(outbuf, mdrcnt);
+ }
+ return -1;
+}
+
/****************************************************************************
the buffer was too small
****************************************************************************/
-static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
+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)
@@ -2522,7 +3461,7 @@ static BOOL api_TooSmall(int cnum,int uid, char *param,char *data,
/****************************************************************************
the request is not supported
****************************************************************************/
-static BOOL api_Unsupported(int cnum,int uid, char *param,char *data,
+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)
@@ -2547,17 +3486,21 @@ struct
{
char *name;
int id;
- BOOL (*fn)();
+ BOOL (*fn)(connection_struct *,uint16,char *,char *,
+ int,int,char **,char **,int *,int *);
int flags;
} api_commands[] = {
{"RNetShareEnum", 0, api_RNetShareEnum,0},
{"RNetShareGetInfo", 1, api_RNetShareGetInfo,0},
{"RNetServerGetInfo", 13, api_RNetServerGetInfo,0},
+ {"RNetGroupGetUsers", 52, api_RNetGroupGetUsers,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},
+ {"WPrintQueuePause", 74, api_WPrintQueuePurge,0},
+ {"WPrintQueueResume", 75, api_WPrintQueuePurge,0},
{"WPrintJobEnumerate",76, api_WPrintJobEnumerate,0},
{"WPrintJobGetInfo", 77, api_WPrintJobGetInfo,0},
{"RDosPrintJobDel", 81, api_RDosPrintJobDel,0},
@@ -2575,16 +3518,19 @@ struct
{"WPrintDriverEnum", 205, api_WPrintDriverEnum,0},
{"WPrintQProcEnum", 206, api_WPrintQProcEnum,0},
{"WPrintPortEnum", 207, api_WPrintPortEnum,0},
+ {"SamOEMChangePassword", 214, api_SamOEMChangePassword,0},
{NULL, -1, api_Unsupported,0}};
/****************************************************************************
handle remote api calls
****************************************************************************/
-static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
+static 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 = SVAL(params,0);
+ struct mem_buf rdata_buf;
+ struct mem_buf rparam_buf;
char *rdata = NULL;
char *rparam = NULL;
int rdata_len = 0;
@@ -2599,39 +3545,50 @@ static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
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;
+ 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,
+ 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(cnum,uid,params,data,mdrcnt,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(cnum,uid,params,data,mdrcnt,mprcnt,
+ api_Unsupported(conn,vuid,params,data,mdrcnt,mprcnt,
&rdata,&rparam,&rdata_len,&rparam_len);
+ mem_create(&rdata_buf , rdata , rdata_len , 0, False);
+ mem_create(&rparam_buf, rparam, rparam_len, 0, False);
+
+ rdata_buf.offset.start = 0;
+ rdata_buf.offset.end = rdata_len;
+
+ rparam_buf.offset.start = 0;
+ rparam_buf.offset.end = rparam_len;
/* now send the reply */
- send_trans_reply(outbuf,rdata,rparam,NULL,rdata_len,rparam_len,0);
+ send_trans_reply(outbuf, &rdata_buf, &rparam_buf, NULL, 0, 0);
- if (rdata)
- free(rdata);
- if (rparam)
- free(rparam);
+ if (rdata ) free(rdata);
+ if (rparam) free(rparam);
return(-1);
}
@@ -2639,141 +3596,170 @@ static int api_reply(int cnum,int uid,char *outbuf,char *data,char *params,
/****************************************************************************
handle named pipe commands
****************************************************************************/
-static int named_pipe(int cnum,int uid, char *outbuf,char *name,
+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)
{
+ DEBUG(3,("named pipe command on <%s> name\n", name));
+
+ if (strequal(name,"LANMAN"))
+ {
+ return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
+ }
- if (strequal(name,"LANMAN"))
- return(api_reply(cnum,uid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt));
+ if (strlen(name) < 1)
+ {
+ return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
+ }
- DEBUG(3,("named pipe command on <%s> 0x%X setup1=%d\n",
- name,(int)setup[0],(int)setup[1]));
-
- return(0);
+ if (setup)
+ {
+ DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
+ }
+
+ return 0;
}
/****************************************************************************
reply to a SMBtrans
****************************************************************************/
-int reply_trans(char *inbuf,char *outbuf)
+int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
{
- 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);
+ fstring name;
+
+ 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);
+
+ bzero(name, sizeof(name));
+ fstrcpy(name,smb_buf(inbuf));
+
+ if (dscnt > tdscnt || pscnt > tpscnt) {
+ exit_server("invalid trans parameters\n");
+ }
- 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 (tdscnt) {
+ if((data = (char *)malloc(tdscnt)) == NULL) {
+ DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
+ return(ERROR(ERRDOS,ERRnomem));
+ }
+ memcpy(data,smb_base(inbuf)+dsoff,dscnt);
+ }
+ if (tpscnt) {
+ if((params = (char *)malloc(tpscnt)) == NULL) {
+ DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
+ return(ERROR(ERRDOS,ERRnomem));
+ }
+ memcpy(params,smb_base(inbuf)+psoff,pscnt);
+ }
- 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);
- }
+ if (suwcnt) {
+ int i;
+ if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
+ DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", suwcnt * sizeof(uint16)));
+ return(ERROR(ERRDOS,ERRnomem));
+ }
+ for (i=0;i<suwcnt;i++)
+ setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
+ }
- /* 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);
+ send_smb(Client,outbuf);
}
-
- 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) != SMBtrans)) || !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" ));
+ }
+ if (params) free(params);
+ if (data) free(data);
+ if (setup) free(setup);
+ return(ERROR(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\n");
+ }
+
+ 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) {
+ DEBUG(5,("calling named_pipe\n"));
+ outsize = named_pipe(conn,vuid,outbuf,name+strlen("\\PIPE\\"),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));
+
+ if (data) free(data);
+ if (params) free(params);
+ if (setup) free(setup);
+
+ if (close_on_completion)
+ close_cnum(conn,vuid);
- return(outsize);
+ if (one_way)
+ return(-1);
+
+ if (outsize == 0)
+ return(ERROR(ERRSRV,ERRnosupport));
+
+ return(outsize);
}
-
-
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c
index 8f1490c528d..f0d5a9d85ca 100644
--- a/source/smbd/mangle.c
+++ b/source/smbd/mangle.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Name mangling
- 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,101 +19,346 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/* -------------------------------------------------------------------------- **
+ * Notable problems...
+ *
+ * March/April 1998 CRH
+ * - Many of the functions in this module overwrite string buffers passed to
+ * them. This causes a variety of problems and is, generally speaking,
+ * dangerous and scarry. See the kludge notes in name_map_mangle()
+ * below.
+ * - It seems that something is calling name_map_mangle() twice. The
+ * first call is probably some sort of test. Names which contain
+ * illegal characters are being doubly mangled. I'm not sure, but
+ * I'm guessing the problem is in server.c.
+ *
+ * -------------------------------------------------------------------------- **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * History...
+ *
+ * March/April 1998 CRH
+ * Updated a bit. Rewrote is_mangled() to be a bit more selective.
+ * Rewrote the mangled name cache. Added comments here and there.
+ * &c.
+ * -------------------------------------------------------------------------- **
+ */
+
#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)
-{
- int res = 0;
- int c;
- int i=0;
- while (*s)
- {
- c = *s;
- res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
- s++; i++;
- }
- return(res);
-}
+/* -------------------------------------------------------------------------- **
+ * External Variables...
+ */
+
+extern int DEBUGLEVEL; /* Global debug level. */
+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. */
+
+/* -------------------------------------------------------------------------- **
+ * Other stuff...
+ *
+ * magic_char - This is the magic char used for mangling. It's
+ * global. There is a call to lp_magicchar() in server.c
+ * that is used to override the initial value.
+ *
+ * basechars - The set of 36 characters used for name mangling. This
+ * is static (scope is this file only).
+ *
+ * base36() - Macro used to select a character from basechars (i.e.,
+ * base36(n) will return the nth digit, modulo 36).
+ *
+ * chartest - array 0..255. The index range is the set of all possible
+ * values of a byte. For each byte value, the content is a
+ * two nibble pair. See BASECHAR_MASK and ILLEGAL_MASK,
+ * below.
+ *
+ * ct_initialized - False until the chartest array has been initialized via
+ * a call to init_chartest().
+ *
+ * BASECHAR_MASK - Masks the upper nibble of a one-byte value.
+ *
+ * ILLEGAL_MASK - Masks the lower nibble of a one-byte value.
+ *
+ * isbasecahr() - Given a character, check the chartest array to see
+ * if that character is in the basechars set. This is
+ * faster than using strchr().
+ *
+ * isillegal() - Given a character, check the chartest array to see
+ * if that character is in the illegal characters set.
+ * This is faster than using strchr().
+ *
+ * mangled_cache - Cache header used for storing mangled -> original
+ * reverse maps.
+ *
+ * mc_initialized - False until the mangled_cache structure has been
+ * initialized via a call to reset_mangled_cache().
+ *
+ * MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
+ * cache. A value of 0 indicates "infinite".
+ *
+ * MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the
+ * cache. When the cache was kept as an array of 256
+ * byte strings, the default cache size was 50 entries.
+ * This required a fixed 12.5Kbytes of memory. The
+ * mangled stack parameter is no longer used (though
+ * this might change). We're now using a fixed 16Kbyte
+ * maximum cache size. This will probably be much more
+ * than 50 entries.
+ */
-/****************************************************************************
-return True if a name is a special msdos reserved name
-****************************************************************************/
-static BOOL is_reserved_msdos(char *fname)
-{
+char magic_char = '~';
+
+static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static unsigned char chartest[256] = { 0 };
+static BOOL ct_initialized = False;
+
+#define base36(V) ((char)(basechars[(V) % 36]))
+#define BASECHAR_MASK 0xf0
+#define ILLEGAL_MASK 0x0f
+#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
+#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
+
+static ubi_cacheRoot mangled_cache[1] = { { { 0 }, 0, 0, 0, 0, 0, 0} };
+static BOOL mc_initialized = False;
+#define MANGLED_CACHE_MAX_ENTRIES 0
+#define MANGLED_CACHE_MAX_MEMORY 16384
+
+
+/* -------------------------------------------------------------------------- **
+ * Functions...
+ */
+
+/* ************************************************************************** **
+ * Initialize the static character test array.
+ *
+ * Input: none
+ *
+ * Output: none
+ *
+ * Notes: This function changes (loads) the contents of the <chartest>
+ * array. The scope of <chartest> is this file.
+ *
+ * ************************************************************************** **
+ */
+static void init_chartest( void )
+ {
+ char *illegalchars = "*\\/?<>|\":";
+ unsigned char *s;
+
+ bzero( (char *)chartest, 256 );
+
+ for( s = (unsigned char *)illegalchars; *s; s++ )
+ chartest[*s] = ILLEGAL_MASK;
+
+ for( s = (unsigned char *)basechars; *s; s++ )
+ chartest[*s] |= BASECHAR_MASK;
+
+ ct_initialized = True;
+ } /* init_chartest */
+
+/* ************************************************************************** **
+ * Return True if a name is a special msdos reserved name.
+ *
+ * Input: fname - String containing the name to be tested.
+ *
+ * Output: True, if the name matches one of the list of reserved names.
+ *
+ * Notes: This is a static function called by is_8_3(), below.
+ *
+ * ************************************************************************** **
+ */
+static BOOL is_reserved_msdos( char *fname )
+ {
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);
-}
-
-
-
-/****************************************************************************
-return True if a name is in 8.3 dos format
-****************************************************************************/
-BOOL is_8_3(char *fname)
-{
- int len;
+ p = strchr(upperFname,'.');
+ if( p )
+ *p = '\0';
+
+ strupper( upperFname );
+ p = upperFname + 1;
+ switch( upperFname[0] )
+ {
+ case 'A':
+ if( 0 == strcmp( p, "UX" ) )
+ return( True );
+ break;
+ case 'C':
+ if( (0 == strcmp( p, "LOCK$" ))
+ || (0 == strcmp( p, "ON" ))
+ || (0 == strcmp( p, "OM1" ))
+ || (0 == strcmp( p, "OM2" ))
+ || (0 == strcmp( p, "OM3" ))
+ || (0 == strcmp( p, "OM4" ))
+ )
+ return( True );
+ break;
+ case 'L':
+ if( (0 == strcmp( p, "PT1" ))
+ || (0 == strcmp( p, "PT2" ))
+ || (0 == strcmp( p, "PT3" ))
+ )
+ return( True );
+ break;
+ case 'N':
+ if( 0 == strcmp( p, "UL" ) )
+ return( True );
+ break;
+ case 'P':
+ if( 0 == strcmp( p, "RN" ) )
+ return( True );
+ break;
+ }
+
+ return( False );
+ } /* is_reserved_msdos */
+
+/* ************************************************************************** **
+ * Determine whether or not a given name contains illegal characters, even
+ * long names.
+ *
+ * Input: name - The name to be tested.
+ *
+ * Output: True if an illegal character was found in <name>, else False.
+ *
+ * Notes: This is used to test a name on the host system, long or short,
+ * for characters that would be illegal on most client systems,
+ * particularly DOS and Windows systems. Unix and AmigaOS, for
+ * example, allow a filenames which contain such oddities as
+ * quotes ("). If a name is found which does contain an illegal
+ * character, it is mangled even if it conforms to the 8.3
+ * format.
+ *
+ * ************************************************************************** **
+ */
+static BOOL is_illegal_name( char *name )
+ {
+ unsigned char *s;
+ int skip;
+
+ if( !name )
+ return( True );
+
+ if( !ct_initialized )
+ init_chartest();
+
+ s = (unsigned char *)name;
+ while( *s )
+ {
+ skip = skip_multibyte_char( *s );
+ if( skip != 0 )
+ {
+ s += skip;
+ }
+ else
+ {
+ if( isillegal( *s ) )
+ return( True );
+ else
+ s++;
+ }
+ }
+
+ return( False );
+ } /* is_illegal_name */
+
+/* ************************************************************************** **
+ * Return True if the name *could be* a mangled name.
+ *
+ * Input: s - A path name - in UNIX pathname format.
+ *
+ * Output: True if the name matches the pattern described below in the
+ * notes, else False.
+ *
+ * Notes: The input name is *not* tested for 8.3 compliance. This must be
+ * done separately. This function returns true if the name contains
+ * a magic character followed by excactly two characters from the
+ * basechars list (above), which in turn are followed either by the
+ * nul (end of string) byte or a dot (extension) or by a '/' (end of
+ * a directory name).
+ *
+ * ************************************************************************** **
+ */
+BOOL is_mangled( char *s )
+ {
+ char *magic;
+
+ if( !ct_initialized )
+ init_chartest();
+
+ magic = strchr( s, magic_char );
+ while( magic && magic[1] && magic[2] ) /* 3 chars, 1st is magic. */
+ {
+ if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
+ && isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */
+ && isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */
+ return( True ); /* If all above, then true, */
+ magic = strchr( magic+1, magic_char ); /* else seek next magic. */
+ }
+ return( False );
+ } /* is_mangled */
+
+/* ************************************************************************** **
+ * Return True if the name is a valid DOS name in 8.3 DOS format.
+ *
+ * Input: fname - File name to be checked.
+ * check_case - If True, and if case_mangle is True, then the
+ * name will be checked to see if all characters
+ * are the correct case. See case_mangle and
+ * case_default above.
+ *
+ * Output: True if the name is a valid DOS name, else FALSE.
+ *
+ * ************************************************************************** **
+ */
+BOOL is_8_3( char *fname, BOOL check_case )
+ {
+ int len;
+ int l;
+ int skip;
+ char *p;
char *dot_pos;
- char *slash_pos = strrchr(fname,'/');
- int l;
+ char *slash_pos = strrchr( fname, '/' );
+
+ /* If there is a directory path, skip it. */
+ if( slash_pos )
+ fname = slash_pos + 1;
+ len = strlen( fname );
- if (slash_pos) fname = slash_pos+1;
- len = strlen(fname);
+ DEBUG( 5, ( "Checking %s for 8.3\n", fname ) );
- dot_pos = strchr(fname,'.');
+ /* Can't be 0 chars or longer than 12 chars */
+ if( (len == 0) || (len > 12) )
+ return( False );
- DEBUG(5,("checking %s for 8.3\n",fname));
+ /* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
+ if( is_reserved_msdos( fname ) )
+ return( False );
- if (case_mangle)
- switch (case_default)
+ /* Check that all characters are the correct case, if asked to do so. */
+ if( check_case && case_mangle )
+ {
+ switch( case_default )
{
case CASE_LOWER:
- if (strhasupper(fname)) return(False);
- break;
+ if( strhasupper( fname ) )
+ return(False);
+ break;
case CASE_UPPER:
- if (strhaslower(fname)) return(False);
- break;
+ 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 */
+ /* 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
@@ -122,180 +367,280 @@ BOOL is_8_3(char *fname)
/* %%% 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)
+ p = fname;
+ dot_pos = NULL;
+ while( *p )
+ {
+ if( (skip = skip_multibyte_char( *p )) != 0 )
+ p += skip;
+ else
{
- if (!isdoschar(*p))
- return(False);
- p++;
- }
-#endif /* KANJI */
- }
+ if( *p == '.' && !dot_pos )
+ dot_pos = (char *)p;
+ else
+ if( !isdoschar( *p ) )
+ return( False );
+ p++;
+ }
+ }
/* no dot and less than 9 means OK */
- if (!dot_pos)
- return(len <= 8);
-
- l = PTR_DIFF(dot_pos,fname);
+ 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);
+ if( l == 0 )
+ return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
/* base can't be greater than 8 */
- if (l > 8)
- return(False);
+ if( l > 8 )
+ return( False );
- if (lp_strip_dot() &&
- len - l == 1 &&
- !strchr(dot_pos+1,'.'))
+ /* see smb.conf(5) for a description of the 'strip dot' parameter. */
+ if( lp_strip_dot()
+ && len - l == 1
+ && !strchr( dot_pos + 1, '.' ) )
{
- *dot_pos = 0;
- return(True);
+ *dot_pos = 0;
+ return( True );
}
/* extension must be between 1 and 3 */
- if ( (len - l < 2 ) || (len - l > 4) )
- return(False);
+ if( (len - l < 2 ) || (len - l > 4) )
+ return( False );
- /* extension can't have a dot */
- if (strchr(dot_pos+1,'.'))
- return(False);
+ /* extensions may not have a dot */
+ if( strchr( dot_pos+1, '.' ) )
+ return( False );
/* must be in 8.3 format */
- return(True);
-}
+ return( True );
+ } /* is_8_3 */
+
+
+/* ************************************************************************** **
+ * Compare two cache keys and return a value indicating their ordinal
+ * relationship.
+ *
+ * Input: ItemPtr - Pointer to a comparison key. In this case, this will
+ * be a mangled name string.
+ * NodePtr - Pointer to a node in the cache. The node structure
+ * will be followed in memory by a mangled name string.
+ *
+ * Output: A signed integer, as follows:
+ * (x < 0) <==> Key1 less than Key2
+ * (x == 0) <==> Key1 equals Key2
+ * (x > 0) <==> Key1 greater than Key2
+ *
+ * Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for
+ * more info.
+ *
+ * ************************************************************************** **
+ */
+static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
+ {
+ char *Key1 = (char *)ItemPtr;
+ char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
+
+ return( StrCaseCmp( Key1, Key2 ) );
+ } /* cache_compare */
+
+/* ************************************************************************** **
+ * Free a cache entry.
+ *
+ * Input: WarrenZevon - Pointer to the entry that is to be returned to
+ * Nirvana.
+ * Output: none.
+ *
+ * Notes: This function gets around the possibility that the standard
+ * free() function may be implemented as a macro, or other evil
+ * subversions (oh, so much fun).
+ *
+ * ************************************************************************** **
+ */
+static void cache_free_entry( ubi_trNodePtr WarrenZevon )
+ {
+ free( WarrenZevon );
+ } /* cache_free_entry */
+
+/* ************************************************************************** **
+ * Initializes or clears the mangled cache.
+ *
+ * Input: none.
+ * Output: none.
+ *
+ * Notes: There is a section below that is commented out. It shows how
+ * one might use lp_ calls to set the maximum memory and entry size
+ * of the cache. You might also want to remove the constants used
+ * in ubi_cacheInit() and replace them with lp_ calls. If so, then
+ * the calls to ubi_cacheSetMax*() would be moved into the else
+ * clause. Another option would be to pass in the max_entries and
+ * max_memory values as parameters. crh 09-Apr-1998.
+ *
+ * ************************************************************************** **
+ */
+void reset_mangled_cache( void )
+ {
+ if( !mc_initialized )
+ {
+ (void)ubi_cacheInit( mangled_cache,
+ cache_compare,
+ cache_free_entry,
+ MANGLED_CACHE_MAX_ENTRIES,
+ MANGLED_CACHE_MAX_MEMORY );
+ mc_initialized = True;
+ }
+ else
+ {
+ (void)ubi_cacheClear( mangled_cache );
+ }
+ /*
+ (void)ubi_cacheSetMaxEntries( mangled_cache, lp_mangled_cache_entries() );
+ (void)ubi_cacheSetMaxMemory( mangled_cache, lp_mangled_cache_memory() );
+ */
+ } /* reset_mangled_cache */
+
+
+/* ************************************************************************** **
+ * Add a mangled name into the cache.
+ *
+ * Notes: If the mangled cache has not been initialized, then the
+ * function will simply fail. It could initialize the cache,
+ * but that's not the way it was done before I changed the
+ * cache mechanism, so I'm sticking with the old method.
+ *
+ * If the extension of the raw name maps directly to the
+ * extension of the mangled name, then we'll store both names
+ * *without* extensions. That way, we can provide consistant
+ * reverse mangling for all names that match. The test here is
+ * a bit more careful than the one done in earlier versions of
+ * mangle.c:
+ *
+ * - the extension must exist on the raw name,
+ * - it must be all lower case
+ * - it must match the mangled extension (to prove that no
+ * mangling occurred).
+ *
+ * crh 07-Apr-1998
+ *
+ * ************************************************************************** **
+ */
+static void cache_mangled_name( char *mangled_name, char *raw_name )
+ {
+ ubi_cacheEntryPtr new_entry;
+ char *s1;
+ char *s2;
+ int mangled_len;
+ int raw_len;
+ int i;
+
+ /* If the cache isn't initialized, give up. */
+ if( !mc_initialized )
+ return;
+ /* Init the string lengths. */
+ mangled_len = strlen( mangled_name );
+ raw_len = strlen( raw_name );
-/*
-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;
-
-/****************************************************************************
-create the mangled stack
-****************************************************************************/
-void create_mangled_stack(int size)
-{
- if (mangled_stack)
+ /* See if the extensions are unmangled. If so, store the entry
+ * without the extension, thus creating a "group" reverse map.
+ */
+ s1 = strrchr( mangled_name, '.' );
+ if( s1 && (s2 = strrchr( raw_name, '.' )) )
{
- free(mangled_stack);
- mangled_stack_size = 0;
- mangled_stack_len = 0;
+ i = 1;
+ while( s1[i] && (tolower( s1[1] ) == s2[i]) )
+ i++;
+ if( !s1[i] && !s2[i] )
+ {
+ mangled_len -= i;
+ raw_len -= i;
+ }
}
- if (size > 0)
- mangled_stack = (fstring *)malloc(sizeof(fstring)*size);
- if (mangled_stack) mangled_stack_size = size;
-}
-
-/****************************************************************************
-push a mangled name onto the stack
-****************************************************************************/
-static void push_mangled_name(char *s)
-{
- int i;
- char *p;
- if (!mangled_stack)
+ /* Allocate a new cache entry. If the allcoation fails, just return. */
+ i = sizeof( ubi_cacheEntry ) + mangled_len + raw_len + 2;
+ new_entry = malloc( i );
+ if( !new_entry )
return;
- for (i=0;i<mangled_stack_len;i++)
- if (strcmp(s,mangled_stack[i]) == 0)
+ /* Fill the new cache entry, and add it to the cache. */
+ s1 = (char *)(new_entry + 1);
+ s2 = (char *)&(s1[mangled_len + 1]);
+ (void)StrnCpy( s1, mangled_name, mangled_len );
+ (void)StrnCpy( s2, raw_name, raw_len );
+ ubi_cachePut( mangled_cache, i, new_entry, s1 );
+ } /* cache_mangled_name */
+
+/* ************************************************************************** **
+ * Check for a name on the mangled name stack
+ *
+ * Input: s - Input *and* output string buffer.
+ *
+ * Output: True if the name was found in the cache, else False.
+ *
+ * Notes: If a reverse map is found, the function will overwrite the string
+ * space indicated by the input pointer <s>. This is frightening.
+ * It should be rewritten to return NULL if the long name was not
+ * found, and a pointer to the long name if it was found.
+ *
+ * ************************************************************************** **
+ */
+BOOL check_mangled_cache( char *s )
+ {
+ ubi_cacheEntryPtr FoundPtr;
+ char *ext_start = NULL;
+ char *found_name;
+
+ /* If the cache isn't initialized, give up. */
+ if( !mc_initialized )
+ return( False );
+
+ FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
+
+ /* If we didn't find the name *with* the extension, try without. */
+ if( !FoundPtr )
+ {
+ ext_start = strrchr( s, '.' );
+ if( ext_start )
{
- array_promote(mangled_stack[0],sizeof(fstring),i);
- return;
+ *ext_start = '\0';
+ FoundPtr = ubi_cacheGet( mangled_cache, (ubi_trItemPtr)s );
+ *ext_start = '.';
}
+ }
- 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);
-}
-
-/****************************************************************************
-check for a name on the mangled name stack
-****************************************************************************/
-BOOL check_mangled_stack(char *s)
-{
- int i;
- pstring tmpname;
- char extension[5];
- char *p = strrchr(s,'.');
- BOOL check_extension = False;
+ /* Okay, if we haven't found it we're done. */
+ if( !FoundPtr )
+ return( False );
- extension[0] = 0;
+ /* If we *did* find it, we need to copy it into the string buffer. */
+ found_name = (char *)(FoundPtr + 1);
+ found_name += (strlen( found_name ) + 1);
- if (!mangled_stack) return(False);
+ DEBUG( 3, ("Found %s on mangled stack ", s) );
- if (p)
- {
- check_extension = True;
- StrnCpy(extension,p,4);
- strlower(extension); /* XXXXXXX */
- }
+ (void)pstrcpy( s, found_name );
+ if( ext_start )
+ (void)pstrcat( s, ext_start );
- for (i=0;i<mangled_stack_len;i++)
- {
- strcpy(tmpname,mangled_stack[i]);
- mangle_name_83(tmpname);
- if (strequal(tmpname,s))
- {
- strcpy(s,mangled_stack[i]);
- break;
- }
- if (check_extension && !strchr(mangled_stack[i],'.'))
- {
- 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;
- }
- }
- }
+ DEBUG( 3, ("as %s\n", s) );
- 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);
- }
+ return( True );
+ } /* check_mangled_cache */
- return(False);
-}
-static char *map_filename(char *s, /* This is null terminated */
- char *pattern, /* This isn't. */
- int len) /* This is the length of pattern. */
-{
+/* ************************************************************************** **
+ * Used only in do_fwd_mangled_map(), below.
+ * ************************************************************************** **
+ */
+static char *map_filename( char *s, /* This is null terminated */
+ char *pattern, /* This isn't. */
+ int len ) /* This is the length of pattern. */
+ {
static pstring matching_bit; /* The bit of the string which matches */
/* a * in pattern if indeed there is a * */
char *sp; /* Pointer into s. */
@@ -303,308 +648,339 @@ static char *map_filename(char *s, /* This is null terminated */
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. */
+ StrnCpy( pat, pattern, len ); /* Get pattern into a proper string! */
+ pstrcpy( matching_bit, "" ); /* Match but no star gets this. */
+ pp = pat; /* Initialize the pointers. */
sp = s;
- if ((len == 1) && (*pattern == '*')) {
+ if( (len == 1) && (*pattern == '*') )
+ {
return NULL; /* Impossible, too ambiguous for */
- /* words! */
- }
+ } /* words! */
- while ((*sp) /* Not the end of the string. */
- && (*pp) /* Not the end of the pattern. */
- && (*sp == *pp) /* The two match. */
- && (*pp != '*')) { /* No wildcard. */
+ 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 == '*') {
+ }
+
+ 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 {
+ 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 */
+ 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. */
+ if( !*sp ) /* Got to the end without a match. */
+ {
+ return( NULL );
+ } /* Still hope for a match. */
+ else
+ {
/* 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. */
+ 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;
+ }
+ if( !*sp && !*pp ) /* Both at end so it matched */
+ return( matching_bit );
else
- return NULL;
+ return( NULL );
+ }
}
}
- }
- return NULL; /* No match. */
-}
-
-
-/* this is the magic char used for mangling */
-char magic_char = '~';
-
-
-/****************************************************************************
-determine whther is name could be a mangled name
-****************************************************************************/
-BOOL is_mangled(char *s)
-{
- char *m = strchr(s,magic_char);
- if (!m) return(False);
-
- /* 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));
-
- /* it could be */
- return(True);
-}
-
-
-
-/****************************************************************************
-return a base 36 character. v must be from 0 to 35.
-****************************************************************************/
-static char base36(int v)
-{
- v = v % 36;
- if (v < 10)
- return('0'+v);
- else /* needed to work around a DEC C compiler bug */
- return('A' + (v-10));
-}
-
-
+ return( NULL ); /* No match. */
+ } /* map_filename */
+
+
+/* ************************************************************************** **
+ * 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.
+ *
+ * (I think Andrew wrote the above, but I'm not sure. -- CRH)
+ *
+ * See 'mangled map' in smb.conf(5).
+ *
+ * ************************************************************************** **
+ */
static void do_fwd_mangled_map(char *s, char *MangledMap)
-{
- /* 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 != '('))
+ DEBUG( 5, ("Mangled Mapping '%s' map '%s'\n", s, MangledMap) );
+ while( *start )
+ {
+ while( (*start) && (*start != '(') )
start++;
- start++; /* Skip the ( */
- if (!*start)
+ if( !*start )
continue; /* Always check for the end. */
+ start++; /* Skip the ( */
end = start; /* Search for the ' ' or a ')' */
- DEBUG(5,("Start of first in pair '%s'\n", start));
- while ((*end) && !((*end == ' ') || (*end == ')')))
+ DEBUG( 5, ("Start of first in pair '%s'\n", start) );
+ while( (*end) && !((*end == ' ') || (*end == ')')) )
end++;
- if (!*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"));
+ }
+ 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));
+ 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. */
+ while( (*end) /* Not the end of string. */
+ && (*end != ')') /* Not the end of the pattern. */
+ && (*end != '*') ) /* Not a wildcard. */
*np++ = *end++;
- if (!*end) {
+ if( !*end )
+ {
start = end;
continue; /* Always check for the end. */
- }
- if (*end == '*') {
- strcpy(np, match_string);
- np += strlen(match_string);
+ }
+ if( *end == '*' )
+ {
+ pstrcpy( 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. */
+ while( (*end) /* Not the end of string. */
+ && (*end != ')') /* Not the end of the pattern. */
+ && (*end != '*') ) /* Not a wildcard. */
*np++ = *end++;
- }
- if (!*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. */
+ pstrcpy( 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++;
- }
-}
-
-/****************************************************************************
-do the actual mangling to 8.3 format
-****************************************************************************/
-void mangle_name_83(char *s)
-{
+ }
+ } /* do_fwd_mangled_map */
+
+/*****************************************************************************
+ * do the actual mangling to 8.3 format
+ * the buffer must be able to hold 13 characters (including the null)
+ *****************************************************************************
+ */
+void mangle_name_83( char *s)
+ {
int csum = str_checksum(s);
char *p;
char extension[4];
char base[9];
int baselen = 0;
int extlen = 0;
+ int skip;
- extension[0]=0;
- base[0]=0;
+ extension[0] = 0;
+ base[0] = 0;
p = strrchr(s,'.');
- if (p && (strlen(p+1)<4) )
+ if( p && (strlen(p+1) < (size_t)4) )
{
- BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
- if (all_normal && p[1] != 0)
- {
- *p = 0;
- csum = str_checksum(s);
- *p = '.';
- }
+ BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */
+
+ if( all_normal && p[1] != 0 )
+ {
+ *p = 0;
+ csum = str_checksum( s );
+ *p = '.';
+ }
}
-
- strupper(s);
+ strupper( s );
- DEBUG(5,("Mangling name %s to ",s));
+ DEBUG( 5, ("Mangling name %s to ",s) );
- if (p)
+ if( p )
{
- if (p == s)
- strcpy(extension,"___");
- else
- {
- *p++ = 0;
- while (*p && extlen < 3)
- {
- if (isdoschar(*p) && *p != '.')
- extension[extlen++] = *p;
- p++;
- }
- extension[extlen] = 0;
- }
+ if( p == s )
+ safe_strcpy( extension, "___", 3 );
+ else
+ {
+ *p++ = 0;
+ while( *p && extlen < 3 )
+ {
+ skip = skip_multibyte_char( *p );
+ switch( skip )
+ {
+ case 2:
+ if( extlen < 2 )
+ {
+ extension[extlen++] = p[0];
+ extension[extlen++] = p[1];
+ }
+ else
+ {
+ extension[extlen++] = base36( (unsigned char)*p );
+ }
+ p += 2;
+ break;
+ case 1:
+ extension[extlen++] = p[0];
+ p++;
+ break;
+ default:
+ if( isdoschar (*p) && *p != '.' )
+ extension[extlen++] = p[0];
+ p++;
+ break;
+ }
+ }
+ extension[extlen] = 0;
+ }
}
p = s;
- while (*p && baselen < 5)
+ while( *p && baselen < 5 )
{
- if (isdoschar(*p) && *p != '.')
- base[baselen++] = *p;
- p++;
+ skip = skip_multibyte_char(*p);
+ switch( skip )
+ {
+ case 2:
+ if( baselen < 4 )
+ {
+ base[baselen++] = p[0];
+ base[baselen++] = p[1];
+ }
+ else
+ {
+ base[baselen++] = base36( (unsigned char)*p );
+ }
+ p += 2;
+ break;
+ case 1:
+ base[baselen++] = p[0];
+ p++;
+ break;
+ default:
+ if( isdoschar( *p ) && *p != '.' )
+ base[baselen++] = p[0];
+ p++;
+ break;
+ }
}
base[baselen] = 0;
csum = csum % (36*36);
- sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
+ (void)slprintf(s, 12, "%s%c%c%c",
+ base, magic_char, base36( csum/36 ), base36( csum ) );
- if (*extension)
+ if( *extension )
{
- strcat(s,".");
- strcat(s,extension);
+ (void)pstrcat( s, "." );
+ (void)pstrcat( s, extension );
}
- DEBUG(5,("%s\n",s));
-}
+ DEBUG( 5, ( "%s\n", s ) );
+
+ } /* mangle_name_83 */
+
+/*****************************************************************************
+ * Convert a filename to DOS format. Return True if successful.
+ *
+ * Input: OutName - Source *and* destination buffer.
+ *
+ * NOTE that OutName must point to a memory space that
+ * is at least 13 bytes in size!
+ *
+ * need83 - If False, name mangling will be skipped unless the
+ * name contains illegal characters. Mapping will still
+ * be done, if appropriate. This is probably used to
+ * signal that a client does not require name mangling,
+ * thus skipping the name mangling even on shares which
+ * have name-mangling turned on.
+ * snum - Share number. This identifies the share in which the
+ * name exists.
+ *
+ * Output: Returns False only if the name wanted mangling but the share does
+ * not have name mangling turned on.
+ *
+ * ****************************************************************************
+ */
+BOOL name_map_mangle(char *OutName, BOOL need83, int snum)
+{
+ char *map;
+ DEBUG(5,("name_map_mangle( %s, %s, %d )\n",
+ OutName, need83?"TRUE":"FALSE", snum));
+#ifdef MANGLE_LONG_FILENAMES
+ if( !need83 && is_illegal_name(OutName) )
+ need83 = True;
+#endif
-/*******************************************************************
- work out if a name is illegal, even for long names
- ******************************************************************/
-static BOOL illegal_name(char *name)
-{
- static unsigned char illegal[256];
- static BOOL initialised=False;
- unsigned char *s;
+ /* apply any name mappings */
+ map = lp_mangled_map(snum);
- 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
+ if (map && *map) {
+ do_fwd_mangled_map( OutName, map );
+ }
+ /* check if it's already in 8.3 format */
+ if (need83 && !is_8_3(OutName, True)) {
+ char *tmp;
- return(False);
-}
+ if (!lp_manglednames(snum)) {
+ return(False);
+ }
+ /* mangle it into 8.3 */
+ tmp = strdup(OutName);
+ mangle_name_83(OutName);
-/****************************************************************************
-convert a filename to DOS format. return True if successful.
-****************************************************************************/
-BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
-{
-#ifdef MANGLE_LONG_FILENAMES
- if (!need83 && illegal_name(OutName)) need83 = True;
-#endif
+ if(tmp) {
+ cache_mangled_name(OutName, tmp);
+ free(tmp);
+ }
+ }
- /* 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);
-}
+ DEBUG(5,("name_map_mangle() ==> [%s]\n", OutName));
+ return(True);
+} /* name_map_mangle */
+/* ========================================================================== */
diff --git a/source/smbd/message.c b/source/smbd/message.c
index 6a96b4c7a9c..001fc652b29 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,7 +25,6 @@
#include "includes.h"
-#include "loadparm.h"
/* look in server.c for some explanation of these variables */
extern int DEBUGLEVEL;
@@ -43,8 +42,8 @@ static void msg_deliver(void)
{
pstring s;
fstring name;
- FILE *f;
int i;
+ int fd;
if (! (*lp_msg_command()))
{
@@ -54,35 +53,33 @@ static void msg_deliver(void)
}
/* put it in a temporary file */
- sprintf(s,"/tmp/msg.XXXXXX");
- strcpy(name,(char *)mktemp(s));
-
- f = fopen(name,"w");
- if (!f)
- {
- DEBUG(1,("can't open message file %s\n",name));
- return;
+ slprintf(s,sizeof(s)-1, "%s/msg.XXXXXX",tmpdir());
+ fstrcpy(name,(char *)mktemp(s));
+
+ fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL,0600);
+ 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++; continue;
}
-
- for (i=0;i<msgpos;)
- {
- if (msgbuf[i]=='\r' && i<(msgpos-1) && msgbuf[i+1]=='\n')
- i++;
- fputc(msgbuf[i++],f);
- }
-
- fclose(f);
+ write(fd,&msgbuf[i++],1);
+ }
+ close(fd);
/* run the command */
if (*lp_msg_command())
{
- strcpy(s,lp_msg_command());
+ pstrcpy(s,lp_msg_command());
string_sub(s,"%s",name);
string_sub(s,"%f",msgfrom);
string_sub(s,"%t",msgto);
- standard_sub(-1,s);
- smbrun(s,NULL);
+ standard_sub_basic(s);
+ smbrun(s,NULL,False);
}
msgpos = 0;
@@ -93,7 +90,8 @@ 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;
@@ -111,8 +109,8 @@ int reply_sends(char *inbuf,char *outbuf)
dest = skip_string(orig,1)+1;
msg = skip_string(dest,1)+1;
- strcpy(msgfrom,orig);
- strcpy(msgto,dest);
+ fstrcpy(msgfrom,orig);
+ fstrcpy(msgto,dest);
len = SVAL(msg,0);
len = MIN(len,1600-msgpos);
@@ -120,7 +118,7 @@ int reply_sends(char *inbuf,char *outbuf)
memcpy(&msgbuf[msgpos],msg+2,len);
msgpos += len;
- DEBUG(3,("%s SMBsends (from %s to %s)\n",timestring(),orig,dest));
+ DEBUG( 3, ( "SMBsends (from %s to %s)\n", orig, dest ) );
msg_deliver();
@@ -131,7 +129,8 @@ 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;
@@ -146,10 +145,10 @@ int reply_sendstrt(char *inbuf,char *outbuf)
orig = smb_buf(inbuf)+1;
dest = skip_string(orig,1)+1;
- strcpy(msgfrom,orig);
- strcpy(msgto,dest);
+ fstrcpy(msgfrom,orig);
+ fstrcpy(msgto,dest);
- DEBUG(3,("%s SMBsendstrt (from %s to %s)\n",timestring(),orig,dest));
+ DEBUG( 3, ( "SMBsendstrt (from %s to %s)\n", msgfrom, msgto ) );
return(outsize);
}
@@ -158,7 +157,8 @@ 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;
@@ -177,7 +177,7 @@ int reply_sendtxt(char *inbuf,char *outbuf)
memcpy(&msgbuf[msgpos],msg+2,len);
msgpos += len;
- DEBUG(3,("%s SMBsendtxt\n",timestring()));
+ DEBUG( 3, ( "SMBsendtxt\n" ) );
return(outsize);
}
@@ -186,7 +186,8 @@ 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;
@@ -195,7 +196,7 @@ int reply_sendend(char *inbuf,char *outbuf)
outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s SMBsendend\n",timestring()));
+ DEBUG(3,("SMBsendend\n"));
msg_deliver();
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
new file mode 100644
index 00000000000..d4e6180261b
--- /dev/null
+++ b/source/smbd/negprot.c
@@ -0,0 +1,419 @@
+/*
+ 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 DEBUGLEVEL;
+extern int Protocol;
+extern int max_recv;
+extern fstring global_myworkgroup;
+extern fstring remote_machine;
+extern pstring myhostname;
+
+/****************************************************************************
+reply for the core protocol
+****************************************************************************/
+static int reply_corep(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 *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 *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);
+ /* Create a token value and add it to the outgoing packet. */
+ if (doencrypt)
+ generate_next_challenge(smb_buf(outbuf));
+
+ 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,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 *outbuf)
+{
+ int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
+ int secword=0;
+ BOOL doencrypt = SMBENCRYPT();
+ time_t t = time(NULL);
+ struct cli_state *cli = NULL;
+ char cryptkey[8];
+ char crypt_len = 0;
+
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
+ }
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+ doencrypt = ((cli->sec_mode & 2) != 0);
+ }
+
+ if (lp_security()>=SEC_USER) secword |= 1;
+ if (doencrypt) secword |= 2;
+
+ if (doencrypt) {
+ crypt_len = 8;
+ if (!cli) {
+ generate_next_challenge(cryptkey);
+ } else {
+ memcpy(cryptkey, cli->cryptkey, 8);
+ set_challenge(cli->cryptkey);
+ }
+ }
+
+ set_message(outbuf,13,crypt_len,True);
+ SSVAL(outbuf,smb_vwv1,secword);
+ SIVAL(outbuf,smb_vwv6,getpid());
+ if (doencrypt)
+ memcpy(smb_buf(outbuf), cryptkey, 8);
+
+ 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);
+}
+
+
+/****************************************************************************
+reply for the nt protocol
+****************************************************************************/
+static int reply_nt1(char *outbuf)
+{
+ /* dual names + lock_and_read + nt SMBs + remote API calls */
+ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
+ (lp_nt_smb_support() ? CAP_NT_SMBS | CAP_RPC_REMOTE_APIS : 0) |
+ (SMB_OFF_T_BITS == 64 ? CAP_LARGE_FILES : 0);
+
+
+/*
+ other valid capabilities which we may support at some time...
+ CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
+ */
+
+ int secword=0;
+ BOOL doencrypt = SMBENCRYPT();
+ time_t t = time(NULL);
+ int data_len;
+ struct cli_state *cli = NULL;
+ char cryptkey[8];
+ char crypt_len = 0;
+
+ if (lp_security() == SEC_SERVER) {
+ cli = server_cryptkey();
+ }
+
+ if (cli) {
+ DEBUG(3,("using password server validation\n"));
+ doencrypt = ((cli->sec_mode & 2) != 0);
+ }
+
+ if (doencrypt) {
+ crypt_len = 8;
+ if (!cli) {
+ generate_next_challenge(cryptkey);
+ } else {
+ memcpy(cryptkey, cli->cryptkey, 8);
+ set_challenge(cli->cryptkey);
+ }
+ }
+
+ if (lp_readraw() && lp_writeraw()) {
+ capabilities |= CAP_RAW_MODE;
+ }
+
+ if (lp_security() >= SEC_USER) secword |= 1;
+ if (doencrypt) secword |= 2;
+
+ /* decide where (if) to put the encryption challenge, and
+ follow it with the OEM'd domain name
+ */
+ data_len = crypt_len + strlen(global_myworkgroup) + 1;
+
+ set_message(outbuf,17,data_len,True);
+ pstrcpy(smb_buf(outbuf)+crypt_len, global_myworkgroup);
+
+ CVAL(outbuf,smb_vwv1) = secword;
+ SSVALS(outbuf,smb_vwv16+1,crypt_len);
+ if (doencrypt)
+ memcpy(smb_buf(outbuf), cryptkey, 8);
+
+ 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,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);
+ SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */
+
+ 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 */
+static 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
+****************************************************************************/
+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;
+
+ 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:
+ 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:
+ set_remote_arch(RA_WINNT);
+ 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);
+
+ /* a special case to stop password server loops */
+ if (Index == 1 && strequal(remote_machine,myhostname) &&
+ (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN))
+ 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;
+ fstrcpy(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, ( "negprot index=%d\n", choice ) );
+
+ return(outsize);
+}
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
new file mode 100644
index 00000000000..4d3572c6a8b
--- /dev/null
+++ b/source/smbd/nttrans.c
@@ -0,0 +1,1467 @@
+/*
+ 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"
+#include "nterr.h"
+
+extern int DEBUGLEVEL;
+extern int Protocol;
+extern int Client;
+extern int smb_read_error;
+extern int global_oplock_break;
+extern int chain_size;
+extern BOOL case_sensitive;
+extern BOOL case_preserve;
+extern BOOL short_case_preserve;
+
+static void remove_pending_change_notify_requests_by_mid(int mid);
+
+static char *known_nt_pipes[] = {
+ "\\LANMAN",
+ "\\srvsvc",
+ "\\samr",
+ "\\wkssvc",
+ "\\NETLOGON",
+ "\\ntlsa",
+ "\\ntsvcs",
+ "\\lsass",
+ "\\lsarpc",
+ "\\winreg",
+ NULL
+};
+
+/****************************************************************************
+ 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 *outbuf, int bufsize, 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 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;
+ }
+
+ /*
+ * 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 */
+ 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(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)
+{
+ switch( create_disposition ) {
+ case FILE_CREATE:
+ /* create if not exist, fail if exist */
+ return 0x10;
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ /* create if not exist, trunc if exist */
+ return 0x12;
+ case FILE_OPEN:
+ /* fail if not exist, open if exists */
+ return 0x1;
+ case FILE_OPEN_IF:
+ /* create if not exist, open if exists */
+ return 0x11;
+ case FILE_OVERWRITE:
+ /* fail if not exist, truncate if exists */
+ return 0x2;
+ default:
+ DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n",
+ create_disposition ));
+ return -1;
+ }
+}
+
+/****************************************************************************
+ Utility function to map share modes.
+****************************************************************************/
+
+static int map_share_mode( uint32 desired_access, uint32 share_access, uint32 file_attributes)
+{
+ int smb_open_mode = -1;
+
+ switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA) ) {
+ case FILE_READ_DATA:
+ smb_open_mode = 0;
+ break;
+ case FILE_WRITE_DATA:
+ smb_open_mode = 1;
+ break;
+ case FILE_READ_DATA|FILE_WRITE_DATA:
+ smb_open_mode = 2;
+ break;
+ }
+
+ if (smb_open_mode == -1) {
+ if(desired_access & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES|
+ WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS))
+ smb_open_mode = 2;
+ else if(desired_access & (FILE_EXECUTE|READ_CONTROL_ACCESS))
+ smb_open_mode = 0;
+ else {
+ DEBUG(0,("map_share_mode: Incorrect value for desired_access = %x\n",
+ desired_access));
+ return -1;
+ }
+ }
+
+ /* Add in the requested share mode - ignore FILE_SHARE_DELETE for now. */
+ switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
+ case FILE_SHARE_READ:
+ smb_open_mode |= (DENY_WRITE<<4);
+ break;
+ case FILE_SHARE_WRITE:
+ smb_open_mode |= (DENY_READ<<4);
+ break;
+ case (FILE_SHARE_READ|FILE_SHARE_WRITE):
+ smb_open_mode |= (DENY_NONE<<4);
+ break;
+ case FILE_SHARE_NONE:
+ smb_open_mode |= (DENY_ALL<<4);
+ break;
+ }
+
+ /*
+ * Handle a O_SYNC request.
+ */
+ if(file_attributes & FILE_FLAG_WRITE_THROUGH)
+ smb_open_mode |= (1<<14);
+
+ 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. */
+ for( i = 0; known_nt_pipes[i]; i++ )
+ if( strequal(fname,known_nt_pipes[i]))
+ break;
+
+ if ( known_nt_pipes[i] == NULL )
+ return(ERROR(ERRSRV,ERRaccess));
+
+ /* 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(ERRSRV,ERRnofids));
+
+ *ppnum = p->pnum;
+
+ return 0;
+}
+
+/****************************************************************************
+ Reply to an NT create and X call.
+****************************************************************************/
+int reply_ntcreate_and_X(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ 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);
+ uint32 fname_len = MIN(((uint32)SVAL(inbuf,smb_ntcreate_NameLength)),
+ ((uint32)sizeof(fname)-1));
+ 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 pnum = -1;
+ 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;
+
+ /*
+ * 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(ERRDOS,ERRbadaccess));
+
+ /*
+ * Now contruct the smb_open_mode value from the desired access
+ * and the share access.
+ */
+
+ if((smb_open_mode = map_share_mode(desired_access,
+ share_access,
+ file_attributes)) == -1) {
+ return(ERROR(ERRDOS,ERRbadaccess));
+ }
+
+ /*
+ * Get the file name.
+ */
+ StrnCpy(fname,smb_buf(inbuf),fname_len);
+ fname[fname_len] = '\0';
+
+ /* If it's an IPC, use the pipe handler. */
+
+ if (IS_IPC(conn)) {
+
+ int ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum);
+ if(ret != 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,("reply_ntcreate_and_X: open pipe = %s\n", fname));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+ }
+
+ /*
+ * Ordinary file or directory.
+ */
+
+ /*
+ * Check if POSIX semantics are wanted.
+ */
+
+ set_posix_case_semantics(file_attributes);
+
+ unix_convert(fname,conn,0,&bad_path,NULL);
+
+ fsp = file_new();
+ if (!fsp) {
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRSRV,ERRnofids));
+ }
+
+ if (!check_name(fname,conn)) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+
+ restore_case_semantics(file_attributes);
+
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ unixmode = unix_mode(conn,smb_attr | aARCH);
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+
+ /*
+ * If it's a request for a directory open, deal with it separately.
+ */
+
+ if(create_options & FILE_DIRECTORY_FILE) {
+ oplock_request = 0;
+
+ open_directory(fsp, conn, fname, smb_ofun,
+ unixmode, &smb_action);
+
+ restore_case_semantics(file_attributes);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ 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. */
+
+ open_file_shared(fsp,conn,fname,smb_open_mode,
+ smb_ofun,unixmode,
+ oplock_request,&rmode,&smb_action);
+
+ if (!fsp->open) {
+ /* We cheat here. The only case we
+ * care about 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. JRA. */
+
+ if(errno == EISDIR) {
+ oplock_request = 0;
+
+ open_directory(fsp, conn, fname, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+ file_free(fsp);
+
+ restore_case_semantics(file_attributes);
+
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ }
+ }
+
+ if(fsp->is_directory) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ close_directory(fsp);
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fsp,False);
+ restore_case_semantics(file_attributes);
+ return(ERROR(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);
+ return(ERROR(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 && fsp->granted_oplock)
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+
+ set_message(outbuf,34,0,True);
+
+ p = outbuf + smb_vwv2;
+
+ /*
+ * Currently as we don't support level II oplocks we just report
+ * exclusive & batch here.
+ */
+
+ SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? 1 : 0));
+ p++;
+ SSVAL(p,0,fsp->fnum);
+ p += 2;
+ SIVAL(p,0,smb_action);
+ p += 4;
+
+ /* Create time. */
+ put_long_date(p,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
+ 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));
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
+/****************************************************************************
+ 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;
+ uint32 flags = IVAL(params,0);
+ uint32 desired_access = IVAL(params,8);
+ uint32 file_attributes = IVAL(params,20);
+ uint32 share_access = IVAL(params,24);
+ uint32 create_disposition = IVAL(params,28);
+ uint32 create_options = IVAL(params,32);
+ uint32 fname_len = MIN(((uint32)IVAL(params,44)),
+ ((uint32)sizeof(fname)-1));
+ 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 pnum = -1;
+ 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;
+
+ /*
+ * 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(ERRDOS,ERRbadaccess));
+
+ /*
+ * Now contruct the smb_open_mode value from the desired access
+ * and the share access.
+ */
+
+ if((smb_open_mode = map_share_mode( desired_access, share_access, file_attributes)) == -1)
+ return(ERROR(ERRDOS,ERRbadaccess));
+
+ /*
+ * Get the file name.
+ */
+
+ StrnCpy(fname,params+53,fname_len);
+ fname[fname_len] = '\0';
+
+ /* If it's an IPC, use the pipe handler. */
+ if (IS_IPC(conn)) {
+ int ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum);
+ if(ret != 0)
+ return ret;
+ smb_action = FILE_WAS_OPENED;
+ } else {
+ /*
+ * Check if POSIX semantics are wanted.
+ */
+
+ set_posix_case_semantics(file_attributes);
+
+ unix_convert(fname,conn,0,&bad_path,NULL);
+
+ fsp = file_new();
+ if (!fsp) {
+ restore_case_semantics(file_attributes);
+ return(ERROR(ERRSRV,ERRnofids));
+ }
+
+ if (!check_name(fname,conn)) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+
+ restore_case_semantics(file_attributes);
+
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ unixmode = unix_mode(conn,smb_attr | aARCH);
+
+ oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+
+ /*
+ * 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.
+ */
+
+ open_directory(fsp, conn, fname, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else {
+
+ /*
+ * Ordinary file case.
+ */
+
+ open_file_shared(fsp,conn,fname,smb_open_mode,smb_ofun,unixmode,
+ oplock_request,&rmode,&smb_action);
+
+ if (!fsp->open) {
+ if((errno == ENOENT) && bad_path) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
+
+ restore_case_semantics(file_attributes);
+
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fsp,False);
+
+ restore_case_semantics(file_attributes);
+
+ return(ERROR(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(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 && fsp->granted_oplock)
+ smb_action |= EXTENDED_OPLOCK_GRANTED;
+ }
+ }
+
+ restore_case_semantics(file_attributes);
+
+ /* Realloc the size of parameters and data we will return */
+ params = *ppparams = Realloc(*ppparams, 69);
+ if(params == NULL)
+ return(ERROR(ERRDOS,ERRnomem));
+
+ p = params;
+ SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? 1 : 0));
+ p += 2;
+ if (IS_IPC(conn)) {
+ SSVAL(p,0,pnum);
+ } else {
+ SSVAL(p,0,fsp->fnum);
+ }
+ p += 2;
+ SIVAL(p,0,smb_action);
+ p += 8;
+
+ if (IS_IPC(conn)) {
+ /*
+ * Deal with pipe return.
+ */
+ 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); /* ? */
+ } else {
+ /*
+ * Deal with file return.
+ */
+ /* Create time. */
+ put_long_date(p,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
+ 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);
+ }
+
+ /* Send the required number of replies */
+ send_nt_replies(outbuf, bufsize, 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);
+ 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));
+
+ return(-1);
+}
+
+/****************************************************************************
+ Reply to an unsolicited SMBNTtranss - just ignore it!
+****************************************************************************/
+int reply_nttranss(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
+{
+ DEBUG(4,("Ignoring nttranss of length %d\n",length));
+ 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;
+ uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)),
+ ((uint32)sizeof(new_name)-1));
+ int outsize = 0;
+
+ CHECK_FSP(fsp, conn);
+ StrnCpy(new_name,params+4,fname_len);
+ new_name[fname_len] = '\0';
+
+ outsize = rename_internals(conn, inbuf, outbuf, fsp->fsp_name,
+ new_name, replace_if_exists);
+ if(outsize == 0) {
+ /*
+ * Rename was successful.
+ */
+ send_nt_replies(outbuf, bufsize, NULL, 0, NULL, 0);
+
+ DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
+ fsp->fsp_name, new_name));
+
+ outsize = -1;
+ }
+
+ return(outsize);
+}
+
+/****************************************************************************
+ 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 the time to check next.
+*****************************************************************************/
+
+typedef struct {
+ ubi_slNode msg_next;
+ files_struct *fsp;
+ connection_struct *conn;
+ time_t next_check_time;
+ time_t modify_time; /* Info from the directory we're monitoring. */
+ time_t status_time; /* Info from the directory we're monitoring. */
+ char request_buf[smb_size];
+} change_notify_buf;
+
+static ubi_slList change_notify_queue = { NULL, (ubi_slNodePtr)&change_notify_queue, 0};
+
+/****************************************************************************
+ Setup the common parts of the return packet and send it.
+*****************************************************************************/
+
+static void change_notify_reply_packet(char *inbuf, int error_class, uint32 error_code)
+{
+ extern int Client;
+ char outbuf[smb_size+38];
+
+ memset(outbuf, '\0', sizeof(outbuf));
+ construct_reply_common(inbuf, outbuf);
+
+ /*
+ * If we're returning a 'too much in the directory changed' we need to
+ * set this is an NT error status flags. If we don't then the (probably
+ * untested) code in the NT redirector has a bug in that it doesn't re-issue
+ * the change notify.... Ah - I *love* it when I get so deeply into this I
+ * can even determine how MS failed to test stuff and why.... :-). JRA.
+ */
+
+ if(error_class == 0) /* NT Error. */
+ SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+
+ ERROR(error_class,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);
+
+ send_smb(Client,outbuf);
+}
+
+/****************************************************************************
+ Delete entries by fnum from the change notify pending queue.
+*****************************************************************************/
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
+{
+ change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+ change_notify_buf *prev = NULL;
+
+ while(cnbp != NULL) {
+ if(cnbp->fsp->fnum == fsp->fnum) {
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ continue;
+ }
+
+ prev = cnbp;
+ cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+ }
+}
+
+/****************************************************************************
+ Delete entries by mid from the change notify pending queue. Always send reply.
+*****************************************************************************/
+
+static void remove_pending_change_notify_requests_by_mid(int mid)
+{
+ change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+ change_notify_buf *prev = NULL;
+
+ while(cnbp != NULL) {
+ if(SVAL(cnbp->request_buf,smb_mid) == mid) {
+ change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_CANCELLED);
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ continue;
+ }
+
+ prev = cnbp;
+ cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+ }
+}
+
+/****************************************************************************
+ Process the change notify queue. Note that this is only called as root.
+*****************************************************************************/
+
+void process_pending_change_notify_queue(time_t t)
+{
+ change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+ change_notify_buf *prev = NULL;
+
+ if(cnbp == NULL)
+ return;
+
+ if(cnbp->next_check_time >= t)
+ return;
+
+ /*
+ * It's time to check. Go through the queue and see if
+ * the timestamps changed.
+ */
+
+ while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
+ SMB_STRUCT_STAT st;
+ files_struct *fsp = cnbp->fsp;
+ connection_struct *conn = cnbp->conn;
+ uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
+ SVAL(cnbp->request_buf,smb_uid);
+
+ /*
+ * Ensure we don't have any old chain_fsp values
+ * sitting around....
+ */
+ chain_size = 0;
+ file_chain_reset();
+
+ if(!become_user(conn,vuid)) {
+ DEBUG(0,("process_pending_change_notify_queue: Unable to become user vuid=%d.\n",
+ vuid ));
+ /*
+ * Remove the entry and return an error to the client.
+ */
+ change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ continue;
+ }
+
+ if(!become_service(conn,True)) {
+ DEBUG(0,("process_pending_change_notify_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+ /*
+ * Remove the entry and return an error to the client.
+ */
+ change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ unbecome_user();
+ continue;
+ }
+
+ if(dos_stat(fsp->fsp_name, &st) < 0) {
+ DEBUG(0,("process_pending_change_notify_queue: Unable to stat directory %s. \
+Error was %s.\n", fsp->fsp_name, strerror(errno) ));
+ /*
+ * Remove the entry and return an error to the client.
+ */
+ change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ unbecome_user();
+ continue;
+ }
+
+ if(cnbp->modify_time != st.st_mtime ||
+ cnbp->status_time != st.st_ctime) {
+ /*
+ * Remove the entry and return a change notify to the client.
+ */
+ DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed\n",
+ fsp->fsp_name ));
+ change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
+ free((char *)ubi_slRemNext( &change_notify_queue, prev));
+ cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+ unbecome_user();
+ continue;
+ }
+
+ unbecome_user();
+
+ /*
+ * Move to the next in the list.
+ */
+ prev = cnbp;
+ cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+ }
+}
+
+/****************************************************************************
+ 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;
+ change_notify_buf *cnbp;
+ SMB_STRUCT_STAT st;
+
+ fsp = file_fsp(setup,4);
+
+ DEBUG(3,("call_nt_transact_notify_change\n"));
+
+ if(!fsp)
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ if((!fsp->open) || (!fsp->is_directory) || (conn != fsp->conn))
+ return(ERROR(ERRDOS,ERRbadfid));
+
+ /*
+ * Now queue an entry on the notify change stack. We timestamp
+ * the entry we are adding so that we know when to scan next.
+ * We only need to save smb_size bytes from this incoming packet
+ * as we will always by returning a 'read the directory yourself'
+ * error.
+ */
+
+ if((cnbp = (change_notify_buf *)malloc(sizeof(change_notify_buf))) == NULL) {
+ DEBUG(0,("call_nt_transact_notify_change: Malloc fail (2) !\n" ));
+ return -1;
+ }
+
+ /*
+ * Store the current timestamp on the directory we are monitoring.
+ */
+
+ if(dos_stat(fsp->fsp_name, &st) < 0) {
+ DEBUG(0,("call_nt_transact_notify_change: Unable to stat name = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+ free((char *)cnbp);
+ return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
+
+ memcpy(cnbp->request_buf, inbuf, smb_size);
+ cnbp->fsp = fsp;
+ cnbp->conn = conn;
+ cnbp->modify_time = st.st_mtime;
+ cnbp->status_time = st.st_ctime;
+
+ cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
+
+ /*
+ * Adding to the tail enables us to check only
+ * the head when scanning for change, as this entry
+ * is forced to have the first timeout expiration.
+ */
+
+ ubi_slAddTail(&change_notify_queue, cnbp);
+
+ DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
+name = %s\n", fsp->fsp_name ));
+
+ return -1;
+}
+
+/****************************************************************************
+ Reply to query a security descriptor - currently this is not implemented (it
+ is planned to be though).
+****************************************************************************/
+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)
+{
+ DEBUG(0,("call_nt_transact_query_security_desc: Currently not implemented.\n"));
+ return(ERROR(ERRSRV,ERRnosupport));
+}
+
+/****************************************************************************
+ Reply to set a security descriptor - currently this is not implemented (it
+ is planned to be though).
+****************************************************************************/
+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)
+{
+ DEBUG(0,("call_nt_transact_set_security_desc: Currently not implemented.\n"));
+ return(ERROR(ERRSRV,ERRnosupport));
+}
+
+/****************************************************************************
+ 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)
+{
+ DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n"));
+ return(ERROR(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;
+
+ 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);
+ return -1;
+ }
+
+ 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)));
+ return(ERROR(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)) {
+ DEBUG(0,("reply_nttrans : Out of memory\n"));
+ return(ERROR(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.\n");
+
+ 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);
+ send_smb(Client,outbuf);
+
+ 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" ));
+ }
+ if(params)
+ free(params);
+ if(data)
+ free(data);
+ if(setup)
+ free(setup);
+ return(ERROR(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\n");
+
+ 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) {
+ uint16 flg2 = SVAL(outbuf,smb_flg2);
+ SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
+ }
+
+ /* Now we must call the relevant NT_TRANS function */
+ switch(function_code) {
+ case NT_TRANSACT_CREATE:
+ outsize = call_nt_transact_create(conn, inbuf, outbuf, length, bufsize,
+ &setup, &params, &data);
+ break;
+ case NT_TRANSACT_IOCTL:
+ outsize = call_nt_transact_ioctl(conn,
+ inbuf, outbuf, length, bufsize,
+ &setup, &params, &data);
+ break;
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
+ length, bufsize,
+ &setup, &params, &data);
+ break;
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
+ length, bufsize,
+ &setup, &params, &data);
+ break;
+ case NT_TRANSACT_RENAME:
+ outsize = call_nt_transact_rename(conn, inbuf, outbuf, length,
+ bufsize,
+ &setup, &params, &data);
+ break;
+
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
+ length, bufsize,
+ &setup, &params, &data);
+ break;
+ default:
+ /* Error in request */
+ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
+ if(setup)
+ free(setup);
+ 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_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.
+ */
+
+ if(setup)
+ free(setup);
+ if(params)
+ free(params);
+ if(data)
+ free(data);
+ 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..2b2f0f05244
--- /dev/null
+++ b/source/smbd/open.c
@@ -0,0 +1,1179 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ file opening and share modes
+ 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 DEBUGLEVEL;
+
+extern pstring sesssetup_user;
+extern uint16 global_oplock_port;
+
+
+/****************************************************************************
+fd support routines - attempt to do a dos_open
+****************************************************************************/
+static int fd_attempt_open(char *fname, int flags, mode_t mode)
+{
+ int fd = dos_open(fname,flags,mode);
+
+ /* Fix for files ending in '.' */
+ if((fd == -1) && (errno == ENOENT) &&
+ (strchr(fname,'.')==NULL))
+ {
+ pstrcat(fname,".");
+ fd = dos_open(fname,flags,mode);
+ }
+
+#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
+ if ((fd == -1) && (errno == ENAMETOOLONG))
+ {
+ int max_len;
+ char *p = strrchr(fname, '/');
+
+ if (p == fname) /* name is "/xxx" */
+ {
+ max_len = pathconf("/", _PC_NAME_MAX);
+ p++;
+ }
+ 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 ((fd = dos_open(fname,flags,mode)) == -1)
+ p[max_len] = tmp;
+ }
+ }
+#endif
+ return fd;
+}
+
+/****************************************************************************
+Cache a uid_t currently with this file open. This is an optimization only
+used when multiple sessionsetup's have been done to one smbd.
+****************************************************************************/
+void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u)
+{
+ if(fd_ptr->uid_cache_count >= sizeof(fd_ptr->uid_users_cache)/sizeof(uid_t))
+ return;
+ fd_ptr->uid_users_cache[fd_ptr->uid_cache_count++] = u;
+}
+
+/****************************************************************************
+Remove a uid_t that currently has this file open. This is an optimization only
+used when multiple sessionsetup's have been done to one smbd.
+****************************************************************************/
+static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u)
+{
+ int i;
+ for(i = 0; i < fd_ptr->uid_cache_count; i++)
+ if(fd_ptr->uid_users_cache[i] == u) {
+ if(i < (fd_ptr->uid_cache_count-1))
+ memmove((char *)&fd_ptr->uid_users_cache[i], (char *)&fd_ptr->uid_users_cache[i+1],
+ sizeof(uid_t)*(fd_ptr->uid_cache_count-1-i) );
+ fd_ptr->uid_cache_count--;
+ }
+ return;
+}
+
+/****************************************************************************
+Check if a uid_t that currently has this file open is present. This is an
+optimization only used when multiple sessionsetup's have been done to one smbd.
+****************************************************************************/
+static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u)
+{
+ int i;
+ for(i = 0; i < fd_ptr->uid_cache_count; i++)
+ if(fd_ptr->uid_users_cache[i] == u)
+ return True;
+ return False;
+}
+
+
+/****************************************************************************
+fd support routines - attempt to re-open an already open fd as O_RDWR.
+Save the already open fd (we cannot close due to POSIX file locking braindamage.
+****************************************************************************/
+static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr)
+{
+ int fd = dos_open( fname, O_RDWR, mode);
+
+ if(fd == -1)
+ return;
+
+ if(fd_ptr->real_open_flags == O_RDONLY)
+ fd_ptr->fd_readonly = fd_ptr->fd;
+ if(fd_ptr->real_open_flags == O_WRONLY)
+ fd_ptr->fd_writeonly = fd_ptr->fd;
+
+ fd_ptr->fd = fd;
+ fd_ptr->real_open_flags = O_RDWR;
+}
+
+/****************************************************************************
+fd support routines - attempt to close the file referenced by this fd.
+Decrements the ref_count and returns it.
+****************************************************************************/
+uint16 fd_attempt_close(file_fd_struct *fd_ptr)
+{
+ extern struct current_user current_user;
+ uint16 ret_ref = fd_ptr->ref_count;
+
+ DEBUG(3,("fd_attempt_close fd = %d, dev = %x, inode = %.0f, open_flags = %d, ref_count = %d.\n",
+ fd_ptr->fd, (unsigned int)fd_ptr->dev, (double)fd_ptr->inode,
+ fd_ptr->real_open_flags,
+ fd_ptr->ref_count));
+
+ SMB_ASSERT(fd_ptr->ref_count != 0);
+
+ fd_ptr->ref_count--;
+ ret_ref = fd_ptr->ref_count;
+
+ if(fd_ptr->ref_count == 0) {
+ if(fd_ptr->fd != -1)
+ close(fd_ptr->fd);
+ if(fd_ptr->fd_readonly != -1)
+ close(fd_ptr->fd_readonly);
+ if(fd_ptr->fd_writeonly != -1)
+ close(fd_ptr->fd_writeonly);
+ /*
+ * Delete this fd_ptr.
+ */
+ fd_ptr_free(fd_ptr);
+ } else {
+ fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
+ }
+
+ return ret_ref;
+}
+
+/****************************************************************************
+fd support routines - check that current user has permissions
+to open this file. Used when uid not found in optimization cache.
+This is really ugly code, as due to POSIX locking braindamage we must
+fork and then attempt to open the file, and return success or failure
+via an exit code.
+****************************************************************************/
+static BOOL check_access_allowed_for_current_user( char *fname, int accmode )
+{
+ pid_t child_pid;
+
+ if((child_pid = fork()) < 0) {
+ DEBUG(0,("check_access_allowed_for_current_user: fork failed.\n"));
+ return False;
+ }
+
+ if(child_pid) {
+ /*
+ * Parent.
+ */
+ pid_t wpid;
+ int status_code;
+ if ((wpid = sys_waitpid(child_pid, &status_code, 0)) < 0) {
+ DEBUG(0,("check_access_allowed_for_current_user: The process is no longer waiting!\n"));
+ return(False);
+ }
+
+ if (child_pid != wpid) {
+ DEBUG(0,("check_access_allowed_for_current_user: We were waiting for the wrong process ID\n"));
+ return(False);
+ }
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if (WIFEXITED(status_code) == 0) {
+ DEBUG(0,("check_access_allowed_for_current_user: The process exited while we were waiting\n"));
+ return(False);
+ }
+ if (WEXITSTATUS(status_code) != 0) {
+ DEBUG(9,("check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access denied.\n", status_code));
+ return(False);
+ }
+#else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+ if(status_code != 0) {
+ DEBUG(9,("check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access denied.\n", status_code));
+ return(False);
+ }
+#endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
+
+ /*
+ * Success - the child could open the file.
+ */
+ DEBUG(9,("check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access allowed.\n", status_code));
+ return True;
+ } else {
+ /*
+ * Child.
+ */
+ int fd;
+ DEBUG(9,("check_access_allowed_for_current_user: Child - attempting to open %s with mode %d.\n", fname, accmode ));
+ if((fd = fd_attempt_open( fname, accmode, 0)) < 0) {
+ /* Access denied. */
+ _exit(EACCES);
+ }
+ close(fd);
+ DEBUG(9,("check_access_allowed_for_current_user: Child - returning ok.\n"));
+ _exit(0);
+ }
+
+ return False;
+}
+
+/****************************************************************************
+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,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
+****************************************************************************/
+static void open_file(files_struct *fsp,connection_struct *conn,
+ char *fname1,int flags,mode_t mode, SMB_STRUCT_STAT *sbuf)
+{
+ extern struct current_user current_user;
+ pstring fname;
+ SMB_STRUCT_STAT statbuf;
+ file_fd_struct *fd_ptr;
+ int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
+
+ fsp->open = False;
+ fsp->fd_ptr = 0;
+ fsp->granted_oplock = False;
+ 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 (conn->read_only && !conn->printer) {
+ /* 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;
+ } 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 handles a bug in Win95 - it doesn't say to create the file when it
+ should */
+ if (conn->printer) {
+ flags |= O_CREAT;
+ }
+
+/*
+ if (flags == O_WRONLY)
+ DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n"));
+*/
+
+ /*
+ * Ensure we have a valid struct stat so we can search the
+ * open fd table.
+ */
+ if(sbuf == 0) {
+ if(dos_stat(fname, &statbuf) < 0) {
+ if(errno != ENOENT) {
+ DEBUG(3,("Error doing stat on file %s (%s)\n",
+ fname,strerror(errno)));
+
+ check_for_pipe(fname);
+ return;
+ }
+ sbuf = 0;
+ } else {
+ sbuf = &statbuf;
+ }
+ }
+
+ /*
+ * Check to see if we have this file already
+ * open. If we do, just use the already open fd and increment the
+ * reference count (fd_get_already_open increments the ref_count).
+ */
+ if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
+ /*
+ * File was already open.
+ */
+
+ /*
+ * Check it wasn't open for exclusive use.
+ */
+ if((flags & O_CREAT) && (flags & O_EXCL)) {
+ fd_ptr->ref_count--;
+ errno = EEXIST;
+ return;
+ }
+
+ /*
+ * Ensure that the user attempting to open
+ * this file has permissions to do so, if
+ * the user who originally opened the file wasn't
+ * the same as the current user.
+ */
+
+ if(!fd_is_in_uid_cache(fd_ptr, (uid_t)current_user.uid)) {
+ if(!check_access_allowed_for_current_user( fname, accmode )) {
+ /* Error - permission denied. */
+ DEBUG(3,("Permission denied opening file %s (flags=%d, accmode = %d)\n",
+ fname, flags, accmode));
+ /* Ensure the ref_count is decremented. */
+ fd_ptr->ref_count--;
+ fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
+ errno = EACCES;
+ return;
+ }
+ }
+
+ fd_add_to_uid_cache(fd_ptr, (uid_t)current_user.uid);
+
+ /*
+ * If not opened O_RDWR try
+ * and do that here - a chmod may have been done
+ * between the last open and now.
+ */
+ if(fd_ptr->real_open_flags != O_RDWR)
+ fd_attempt_reopen(fname, mode, fd_ptr);
+
+ /*
+ * Ensure that if we wanted write access
+ * it has been opened for write, and if we wanted read it
+ * was open for read.
+ */
+ if(((accmode == O_WRONLY) && (fd_ptr->real_open_flags == O_RDONLY)) ||
+ ((accmode == O_RDONLY) && (fd_ptr->real_open_flags == O_WRONLY)) ||
+ ((accmode == O_RDWR) && (fd_ptr->real_open_flags != O_RDWR))) {
+ DEBUG(3,("Error opening (already open for flags=%d) file %s (%s) (flags=%d)\n",
+ fd_ptr->real_open_flags, fname,strerror(EACCES),flags));
+ check_for_pipe(fname);
+ fd_remove_from_uid_cache(fd_ptr, (uid_t)current_user.uid);
+ fd_ptr->ref_count--;
+ return;
+ }
+
+ } else {
+ int open_flags;
+ /* We need to allocate a new file_fd_struct (this increments the
+ ref_count). */
+ if((fd_ptr = fd_get_new()) == 0)
+ return;
+ /*
+ * Whatever the requested flags, attempt read/write access,
+ * as we don't know what flags future file opens may require.
+ * If this fails, try again with the required flags.
+ * Even if we open read/write when only read access was
+ * requested the setting of the can_write flag in
+ * the file_struct will protect us from errant
+ * write requests. We never need to worry about O_APPEND
+ * as this is not set anywhere in Samba.
+ */
+ fd_ptr->real_open_flags = O_RDWR;
+ /* Set the flags as needed without the read/write modes. */
+ open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY);
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode);
+ /*
+ * On some systems opening a file for R/W access on a read only
+ * filesystems sets errno to EROFS.
+ */
+#ifdef EROFS
+ if((fd_ptr->fd == -1) && ((errno == EACCES) || (errno == EROFS))) {
+#else /* No EROFS */
+ if((fd_ptr->fd == -1) && (errno == EACCES)) {
+#endif /* EROFS */
+ if(accmode != O_RDWR) {
+ fd_ptr->fd = fd_attempt_open(fname, open_flags|accmode, mode);
+ fd_ptr->real_open_flags = accmode;
+ }
+ }
+ }
+
+ if ((fd_ptr->fd >=0) &&
+ conn->printer && lp_minprintspace(SNUM(conn))) {
+ pstring dname;
+ SMB_BIG_UINT dum1,dum2,dum3;
+ char *p;
+ pstrcpy(dname,fname);
+ p = strrchr(dname,'/');
+ if (p) *p = 0;
+ if (sys_disk_free(dname,&dum1,&dum2,&dum3) < (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) {
+ if(fd_attempt_close(fd_ptr) == 0)
+ dos_unlink(fname);
+ fsp->fd_ptr = 0;
+ errno = ENOSPC;
+ return;
+ }
+ }
+
+ if (fd_ptr->fd < 0)
+ {
+ DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
+ fname,strerror(errno),flags));
+ /* Ensure the ref_count is decremented. */
+ fd_attempt_close(fd_ptr);
+ check_for_pipe(fname);
+ return;
+ }
+
+ if (fd_ptr->fd >= 0)
+ {
+ if(sbuf == 0) {
+ /* Do the fstat */
+ if(sys_fstat(fd_ptr->fd, &statbuf) == -1) {
+ /* Error - backout !! */
+ DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
+ fd_ptr->fd, fname,strerror(errno)));
+ /* Ensure the ref_count is decremented. */
+ fd_attempt_close(fd_ptr);
+ return;
+ }
+ sbuf = &statbuf;
+ }
+
+ /* Set the correct entries in fd_ptr. */
+ fd_ptr->dev = sbuf->st_dev;
+ fd_ptr->inode = sbuf->st_ino;
+
+ fsp->fd_ptr = fd_ptr;
+ conn->num_files_open++;
+ fsp->mode = sbuf->st_mode;
+ GetTimeOfDay(&fsp->open_time);
+ fsp->vuid = current_user.vuid;
+ fsp->size = 0;
+ fsp->pos = -1;
+ fsp->open = True;
+ fsp->mmap_ptr = NULL;
+ fsp->mmap_size = 0;
+ 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 = conn->printer;
+ fsp->modified = False;
+ fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
+ fsp->is_directory = False;
+ fsp->delete_on_close = False;
+ fsp->conn = conn;
+ /*
+ * Note that the file name here is the *untranslated* name
+ * ie. it is still in the DOS codepage sent from the client.
+ * All use of this filename will pass though the sys_xxxx
+ * functions which will do the dos_to_unix translation before
+ * mapping into a UNIX filename. JRA.
+ */
+ string_set(&fsp->fsp_name,fname);
+ fsp->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 (fsp->print_file && lp_postscript(SNUM(conn)) && fsp->can_write) {
+ DEBUG(3,("Writing postscript line\n"));
+ write_file(fsp,"%!\n",3);
+ }
+
+ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
+ *sesssetup_user ? sesssetup_user : conn->user,fsp->fsp_name,
+ BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
+ conn->num_files_open));
+
+ }
+}
+
+/****************************************************************************
+ If it's a read-only file, and we were compiled with mmap enabled,
+ try and mmap the file. This is split out from open_file() above
+ as mmap'ing the file can cause the kernel reference count to
+ be incremented, which can cause kernel oplocks to be refused.
+ Splitting this call off allows the kernel oplock to be granted, then
+ the file mmap'ed.
+****************************************************************************/
+
+static void mmap_open_file(files_struct *fsp)
+{
+#if WITH_MMAP
+ /* mmap it if read-only */
+ if (!fsp->can_write) {
+ fsp->mmap_size = file_size(fsp->fsp_name);
+ if (fsp->mmap_size < MAX_MMAP_SIZE) {
+ fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size,
+ PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0);
+
+ if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr) {
+ DEBUG(3,("Failed to mmap() %s - %s\n",
+ fsp->fsp_name,strerror(errno)));
+ fsp->mmap_ptr = NULL;
+ }
+ }
+ }
+#endif
+}
+
+/****************************************************************************
+ C. Hoch 11/22/95
+ Helper for open_file_shared.
+ Truncate a file after checking locking; close file if locked.
+ **************************************************************************/
+static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, int token,
+ BOOL *share_locked)
+{
+ if (fsp->can_write){
+ SMB_OFF_T mask = ((SMB_OFF_T)0xC) << (SMB_OFF_T_BITS-4);
+
+ if (is_locked(fsp,conn,~mask,0,F_WRLCK)){
+ /* If share modes are in force for this connection we
+ have the share entry locked. Unlock it before closing. */
+ if (*share_locked && lp_share_modes(SNUM(conn)))
+ unlock_share_entry( conn, fsp->fd_ptr->dev,
+ fsp->fd_ptr->inode, token);
+ close_file(fsp,False);
+ /* Share mode no longer locked. */
+ *share_locked = False;
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRlock;
+ } else {
+ sys_ftruncate(fsp->fd_ptr->fd,0);
+ }
+ }
+}
+
+
+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) {
+ int pid = getpid();
+ if (old_deny == new_deny && share_pid == pid)
+ 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 we can open a file with a share mode
+****************************************************************************/
+static int check_share_mode( share_mode_entry *share, int deny_mode,
+ char *fname,
+ BOOL fcbopen, int *flags)
+{
+ int old_open_mode = share->share_mode &0xF;
+ int old_deny_mode = (share->share_mode >>4)&7;
+
+ if (old_deny_mode > 4 || old_open_mode > 2)
+ {
+ DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n",
+ deny_mode,old_deny_mode,old_open_mode,fname));
+ return False;
+ }
+
+ {
+ int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
+ share->pid,fname);
+
+ if ((access_allowed == AFAIL) ||
+ (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) ||
+ (access_allowed == AREAD && *flags == O_WRONLY) ||
+ (access_allowed == AWRITE && *flags == O_RDONLY))
+ {
+ 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,
+ share->pid,fname, fcbopen, *flags, access_allowed));
+ return False;
+ }
+
+ if (access_allowed == AREAD)
+ *flags = O_RDONLY;
+
+ if (access_allowed == AWRITE)
+ *flags = O_WRONLY;
+
+ }
+ return True;
+}
+
+
+/****************************************************************************
+open a file with a share mode
+****************************************************************************/
+void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int share_mode,int ofun,
+ mode_t mode,int oplock_request, int *Access,int *action)
+{
+ int flags=0;
+ int flags2=0;
+ int deny_mode = (share_mode>>4)&7;
+ SMB_STRUCT_STAT sbuf;
+ BOOL file_existed = file_exist(fname,&sbuf);
+ BOOL share_locked = False;
+ BOOL fcbopen = False;
+ int token;
+ SMB_DEV_T dev = 0;
+ SMB_INO_T inode = 0;
+ int num_share_modes = 0;
+
+ fsp->open = False;
+ fsp->fd_ptr = 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 */
+
+ 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 defined(O_SYNC)
+ if (share_mode&(1<<14)) {
+ flags2 |= O_SYNC;
+ }
+#endif /* O_SYNC */
+
+ if (flags != O_RDONLY && file_existed &&
+ (!CAN_WRITE(conn) || IS_DOS_READONLY(dos_mode(conn,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(conn)))
+ {
+ int i;
+ share_mode_entry *old_shares = 0;
+
+ if (file_existed)
+ {
+ dev = sbuf.st_dev;
+ inode = sbuf.st_ino;
+ lock_share_entry(conn, dev, inode, &token);
+ share_locked = True;
+ num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
+ }
+
+ /*
+ * Check if the share modes will give us access.
+ */
+
+ if(share_locked && (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];
+
+ /*
+ * 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(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ {
+
+ DEBUG(5,("open_file_shared: 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, token);
+ if(request_oplock_break(share_entry, dev, inode) == False)
+ {
+ free((char *)old_shares);
+
+ DEBUG(0,("open_file_shared: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
+
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return;
+ }
+ lock_share_entry(conn, dev, inode, &token);
+ broke_oplock = True;
+ break;
+ }
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
+ {
+ free((char *)old_shares);
+ unlock_share_entry(conn, dev, inode, token);
+ errno = EACCES;
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+ return;
+ }
+
+ } /* end for */
+
+ if(broke_oplock)
+ {
+ free((char *)old_shares);
+ num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
+ }
+ } while(broke_oplock);
+ }
+
+ if(old_shares != 0)
+ free((char *)old_shares);
+ }
+
+ DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
+ flags,flags2,(int)mode));
+
+ open_file(fsp,conn,fname,flags|(flags2&~(O_TRUNC)),mode,file_existed ? &sbuf : 0);
+ if (!fsp->open && flags==O_RDWR && errno!=ENOENT && fcbopen)
+ {
+ flags = O_RDONLY;
+ open_file(fsp,conn,fname,flags,mode,file_existed ? &sbuf : 0 );
+ }
+
+ if (fsp->open)
+ {
+ int open_mode=0;
+
+ if((share_locked == False) && lp_share_modes(SNUM(conn)))
+ {
+ /* We created the file - thus we must now lock the share entry before creating it. */
+ dev = fsp->fd_ptr->dev;
+ inode = fsp->fd_ptr->inode;
+ lock_share_entry(conn, dev, inode, &token);
+ share_locked = True;
+ }
+
+ switch (flags)
+ {
+ case O_RDONLY:
+ open_mode = 0;
+ break;
+ case O_RDWR:
+ open_mode = 2;
+ break;
+ case O_WRONLY:
+ open_mode = 1;
+ break;
+ }
+
+ fsp->share_mode = (deny_mode<<4) | open_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;
+ }
+ /* We must create the share mode entry before truncate as
+ truncate can fail due to locking and have to close the
+ file (which expects the share_mode_entry to be there).
+ */
+ if (lp_share_modes(SNUM(conn)))
+ {
+ uint16 port = 0;
+
+ /* JRA. Currently this only services Exlcusive and batch
+ oplocks (no other opens on this file). This needs to
+ be extended to level II oplocks (multiple reader
+ oplocks). */
+
+ if((oplock_request) && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) &&
+ !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp) )
+ {
+ port = global_oplock_port;
+ }
+ else
+ {
+ port = 0;
+ oplock_request = 0;
+ }
+
+ set_share_mode(token, fsp, port, oplock_request);
+ }
+
+ if ((flags2&O_TRUNC) && file_existed)
+ truncate_unless_locked(fsp,conn,token,&share_locked);
+
+ /*
+ * Attempt to mmap a read only file.
+ * Moved until after a kernel oplock may
+ * be granted due to reference count issues. JRA.
+ */
+ mmap_open_file(fsp);
+ }
+
+ if (share_locked && lp_share_modes(SNUM(conn)))
+ unlock_share_entry( conn, dev, inode, token);
+}
+
+
+
+/****************************************************************************
+ Open a directory from an NT SMB call.
+****************************************************************************/
+int open_directory(files_struct *fsp,connection_struct *conn,
+ char *fname, int smb_ofun, mode_t unixmode, int *action)
+{
+ extern struct current_user current_user;
+ SMB_STRUCT_STAT st;
+
+ if (smb_ofun & 0x10) {
+ /*
+ * Create the directory.
+ */
+
+ if(dos_mkdir(fname, unixmode) < 0) {
+ DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
+ fname, strerror(errno) ));
+ return -1;
+ }
+
+ *action = FILE_WAS_CREATED;
+ } else {
+ /*
+ * Check that it *was* a directory.
+ */
+
+ if(dos_stat(fname, &st) < 0) {
+ DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n",
+ fname, strerror(errno) ));
+ return -1;
+ }
+
+ if(!S_ISDIR(st.st_mode)) {
+ DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
+ return -1;
+ }
+ *action = FILE_WAS_OPENED;
+ }
+
+ DEBUG(5,("open_directory: opening directory %s\n",
+ fname));
+
+ /*
+ * Setup the files_struct for it.
+ */
+
+ fsp->fd_ptr = NULL;
+ conn->num_files_open++;
+ fsp->mode = 0;
+ GetTimeOfDay(&fsp->open_time);
+ fsp->vuid = current_user.vuid;
+ fsp->size = 0;
+ fsp->pos = -1;
+ fsp->open = True;
+ fsp->mmap_ptr = NULL;
+ fsp->mmap_size = 0;
+ fsp->can_lock = True;
+ fsp->can_read = False;
+ fsp->can_write = False;
+ fsp->share_mode = 0;
+ fsp->print_file = False;
+ fsp->modified = False;
+ fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
+ fsp->is_directory = True;
+ fsp->conn = conn;
+ /*
+ * Note that the file name here is the *untranslated* name
+ * ie. it is still in the DOS codepage sent from the client.
+ * All use of this filename will pass though the sys_xxxx
+ * functions which will do the dos_to_unix translation before
+ * mapping into a UNIX filename. JRA.
+ */
+ string_set(&fsp->fsp_name,fname);
+ fsp->wbmpx_ptr = NULL;
+
+ return 0;
+}
+
+
+/*******************************************************************
+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;
+ int token;
+ int pid = getpid();
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+
+ if(!lp_share_modes(SNUM(conn)))
+ return True;
+
+ if (dos_stat(fname,&sbuf) == -1) return(True);
+
+ dev = sbuf.st_dev;
+ inode = sbuf.st_ino;
+
+ lock_share_entry(conn, dev, inode, &token);
+ num_share_modes = get_share_modes(conn, token, 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(share_entry->op_type & BATCH_OPLOCK)
+ {
+
+ /*
+ * 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
+ {
+
+ 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, token);
+ if(request_oplock_break(share_entry, dev, inode) == False)
+ {
+ free((char *)old_shares);
+
+ 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));
+
+ return False;
+ }
+ lock_share_entry(conn, dev, inode, &token);
+ broke_oplock = True;
+ break;
+ }
+ }
+
+ /* someone else has a share lock on it, check to see
+ if we can too */
+ if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+ goto free_and_exit;
+
+ } /* end for */
+
+ if(broke_oplock)
+ {
+ free((char *)old_shares);
+ num_share_modes = get_share_modes(conn, token, 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() */
+ ret = True;
+
+free_and_exit:
+
+ unlock_share_entry(conn, dev, inode, token);
+ if(old_shares != NULL)
+ free((char *)old_shares);
+ return(ret);
+}
+
+
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
new file mode 100644
index 00000000000..d5c06312f5f
--- /dev/null
+++ b/source/smbd/oplock.c
@@ -0,0 +1,1085 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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"
+
+extern int DEBUGLEVEL;
+
+/* Oplock ipc UDP socket. */
+static int oplock_sock = -1;
+uint16 global_oplock_port = 0;
+#if defined(HAVE_KERNEL_OPLOCKS)
+static int oplock_pipe_read = -1;
+static int oplock_pipe_write = -1;
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+/* Current number of oplocks we have outstanding. */
+int32 global_oplocks_open = 0;
+BOOL global_oplock_break = False;
+
+extern int smb_read_error;
+
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval);
+
+/****************************************************************************
+ open the oplock IPC socket communication
+****************************************************************************/
+BOOL open_oplock_ipc(void)
+{
+ struct sockaddr_in sock_name;
+ int 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));
+ if (oplock_sock == -1)
+ {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
+address %x. Error was %s\n", 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);
+
+ DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",
+ (int)getpid(), global_oplock_port));
+
+ return True;
+}
+
+/****************************************************************************
+ Read an oplock break message from the either the oplock UDP fd
+ or the kernel oplock pipe fd (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 defined(HAVE_KERNEL_OPLOCKS)
+ if(lp_kernel_oplocks())
+ maxfd = MAX(maxfd, oplock_pipe_read);
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+
+ selrtn = sys_select(maxfd+1,fds,&to);
+
+ /* 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 defined(HAVE_KERNEL_OPLOCKS)
+ if(FD_ISSET(oplock_pipe_read,fds)) {
+ /*
+ * Deal with the kernel <--> smbd
+ * oplock break protocol.
+ */
+
+ oplock_stat_t os;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ char dummy;
+
+ /*
+ * 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) ));
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ dev = (SMB_DEV_T)os.os_dev;
+ inode = (SMB_DEV_T)os.os_ino;
+
+ DEBUG(5,("receive_local_message: kernel oplock break request received for \
+dev = %x, inode = %.0f\n", (unsigned int)dev, (double)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);
+ SIVAL(buffer,KERNEL_OPLOCK_BREAK_DEV_OFFSET,dev);
+
+#ifdef LARGE_SMB_INO_T
+ SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET,inode & 0xFFFFFFFF);
+ SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET+4, (inode >> 32 ) & 0xFFFFFFFF );
+#else /* LARGE_SMB_INO_T */
+ SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET,inode);
+#endif /* LARGE_SMB_INO_T */
+
+ return True;
+ }
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ /*
+ * 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 %x should be 127.0.0.1\n", 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)
+{
+#if defined(HAVE_KERNEL_OPLOCKS)
+ if(lp_kernel_oplocks()) {
+
+ if(fcntl(fsp->fd_ptr->fd, F_OPLKREG, oplock_pipe_write) < 0 ) {
+ if(errno != EAGAIN) {
+ DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
+inode = %.0f. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode,
+ strerror(errno) ));
+ } else {
+ DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+inode = %.0f. Another process had the file open.\n",
+ fsp->fsp_name, fsp->fd_ptr->fd, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode ));
+ }
+ return False;
+ }
+
+ DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
+ fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode));
+
+ }
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f\n",
+ fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode));
+
+ fsp->granted_oplock = True;
+ fsp->sent_oplock_break = False;
+ global_oplocks_open++;
+
+ return True;
+}
+
+/****************************************************************************
+ Attempt to release an oplock on a file. Always succeeds if kernel oplocks are
+ disabled (just clears flags).
+****************************************************************************/
+
+static void release_file_oplock(files_struct *fsp)
+{
+#if defined(HAVE_KERNEL_OPLOCKS)
+
+ if(lp_kernel_oplocks())
+ {
+ if( DEBUGLVL( 10 ))
+ {
+ /*
+ * Check and print out the current kernel
+ * oplock state of this file.
+ */
+ int state = fcntl(fsp->fd_ptr->fd, F_OPLKACK, -1);
+ dbgtext("release_file_oplock: file %s, dev = %x, inode = %.0f has kernel \
+oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
+ (double)fsp->fd_ptr->inode, state );
+ }
+
+ /*
+ * Remote the kernel oplock on this file.
+ */
+
+ if(fcntl(fsp->fd_ptr->fd, F_OPLKACK, OP_REVOKE) < 0)
+ {
+ if( DEBUGLVL( 0 ))
+ {
+ dbgtext("release_file_oplock: Error when removing kernel oplock on file " );
+ dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
+ (double)fsp->fd_ptr->inode, strerror(errno) );
+ }
+ }
+ }
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ fsp->granted_oplock = False;
+ fsp->sent_oplock_break = False;
+ global_oplocks_open--;
+}
+
+/****************************************************************************
+ 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;
+ FD_SET(oplock_sock,fds);
+
+#if defined(HAVE_KERNEL_OPLOCKS)
+ if(lp_kernel_oplocks()) {
+ FD_SET(oplock_pipe_read,fds);
+ maxfd = MAX(maxfd,oplock_pipe_read);
+ }
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ 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;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ uint32 remotepid;
+ struct timeval tval;
+ struct timeval *ptval = NULL;
+
+ 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.
+ */
+
+ switch(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET))
+ {
+#if defined(HAVE_KERNEL_OPLOCKS)
+ case KERNEL_OPLOCK_BREAK_CMD:
+ /* Ensure that the msg length is correct. */
+ if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN)
+ {
+ DEBUG(0,("process_local_message: incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, \
+should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+ {
+ /*
+ * Warning - beware of SMB_INO_T <> 4 bytes. !!
+ */
+#ifdef LARGE_SMB_INO_T
+ SMB_INO_T inode_low = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET);
+ SMB_INO_T inode_high = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET + 4);
+ inode = inode_low | (inode_high << 32);
+#else /* LARGE_SMB_INO_T */
+ inode = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET);
+#endif /* LARGE_SMB_INO_T */
+
+ dev = IVAL(msg_start,KERNEL_OPLOCK_BREAK_DEV_OFFSET);
+
+ ptval = NULL;
+
+ DEBUG(5,("process_local_message: kernel oplock break request for \
+file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
+ }
+ break;
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ case 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", msg_len, OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+ {
+ /*
+ * Warning - beware of SMB_INO_T <> 4 bytes. !!
+ */
+#ifdef LARGE_SMB_INO_T
+ SMB_INO_T inode_low = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+ SMB_INO_T inode_high = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET + 4);
+ inode = inode_low | (inode_high << 32);
+#else /* LARGE_SMB_INO_T */
+ inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+#endif /* LARGE_SMB_INO_T */
+
+ dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+
+ tval.tv_sec = (time_t)IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
+ tval.tv_usec = (long)IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+
+ ptval = &tval;
+
+ remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+
+ DEBUG(5,("process_local_message: oplock break request from \
+pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)dev, (double)inode));
+ }
+ 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", msg_len, OPLOCK_BREAK_MSG_LEN));
+ return False;
+ }
+
+ {
+ /*
+ * Warning - beware of SMB_INO_T <> 4 bytes. !!
+ */
+#ifdef LARGE_SMB_INO_T
+ SMB_INO_T inode_low = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+ SMB_INO_T inode_high = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET + 4);
+ inode = inode_low | (inode_high << 32);
+#else /* LARGE_SMB_INO_T */
+ inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+#endif /* LARGE_SMB_INO_T */
+
+ remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+ dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+
+ DEBUG(0,("process_local_message: unsolicited oplock break reply from \
+pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)dev, (double)inode));
+
+ }
+ 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(global_oplocks_open != 0)
+ {
+ if(oplock_break(dev, inode, ptval) == 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 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);
+
+ bzero((char *)&toaddr,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",
+ 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\n",
+ remotepid, from_port, (unsigned int)dev, (double)inode));
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+{
+ extern struct current_user current_user;
+ extern int Client;
+ char *inbuf = NULL;
+ char *outbuf = NULL;
+ files_struct *fsp = NULL;
+ time_t start_time;
+ BOOL shutdown_server = False;
+ connection_struct *saved_conn;
+ int saved_vuid;
+ pstring saved_dir;
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "oplock_break: called for dev = %x, inode = %.0f.\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Current global_oplocks_open = %d\n", global_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_dit(dev, inode, tval);
+
+ if(fsp == NULL)
+ {
+ /* The file could have been closed in the meantime - return success. */
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "oplock_break: cannot find open file with " );
+ dbgtext( "dev = %x, inode = %.0f ", (unsigned int)dev, (double)inode);
+ dbgtext( "allowing break to succeed.\n" );
+ }
+ return True;
+ }
+
+ /* 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->granted_oplock)
+ {
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "oplock_break: file %s ", fsp->fsp_name );
+ dbgtext( "(dev = %x, inode = %.0f) has no oplock.\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Allowing break to succeed regardless.\n" );
+ }
+ return True;
+ }
+
+ /* 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)\n", (unsigned int)dev, (double)inode );
+ }
+
+ /* 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;
+ }
+
+ /* 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 + SAFETY_MARGIN))==NULL)
+ {
+ DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+ return False;
+ }
+
+ if((outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+ {
+ DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+ free(inbuf);
+ inbuf = NULL;
+ return False;
+ }
+
+ /* Prepare the SMBlockingX message. */
+ bzero(outbuf,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);
+ /* Change this when we have level II oplocks. */
+ SCVAL(outbuf,smb_vwv3+1,OPLOCKLEVEL_NONE);
+
+ send_smb(Client, outbuf);
+
+ /* Remember we just sent an oplock break on this file. */
+ fsp->sent_oplock_break = True;
+
+ /* 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_conn = fsp->conn;
+ saved_vuid = current_user.vuid;
+ GetWd(saved_dir);
+ unbecome_user();
+ /* Save the chain fnum. */
+ file_chain_save();
+
+ while(OPEN_FSP(fsp) && fsp->granted_oplock)
+ {
+ if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
+ {
+ /*
+ * Die if we got an error.
+ */
+
+ if (smb_read_error == READ_EOF)
+ DEBUG( 0, ( "oplock_break: end of file from client\n" ) );
+
+ if (smb_read_error == READ_ERROR)
+ DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) );
+
+ if (smb_read_error == READ_TIMEOUT)
+ DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n",
+ OPLOCK_BREAK_TIMEOUT ) );
+
+ DEBUGADD( 0, ( "oplock_break failed for file %s ", fsp->fsp_name ) );
+ DEBUGADD( 0, ( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode));
+
+ shutdown_server = True;
+ 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).\n", (unsigned int)dev, (double)inode );
+ }
+ shutdown_server = True;
+ break;
+ }
+ }
+
+ /*
+ * Go back to being the user who requested the oplock
+ * break.
+ */
+ if(!become_user(saved_conn, saved_vuid))
+ {
+ DEBUG( 0, ( "oplock_break: unable to re-become user!" ) );
+ DEBUGADD( 0, ( "Shutting down server\n" ) );
+ close_sockets();
+ close(oplock_sock);
+ exit_server("unable to re-become user");
+ }
+ /* Including the directory. */
+ ChDir(saved_dir);
+
+ /* Restore the chain fnum. */
+ file_chain_restore();
+
+ /* Free the buffers we've been using to recurse. */
+ free(inbuf);
+ free(outbuf);
+
+ /* We need this in case a readraw crossed on the wire. */
+ if(global_oplock_break)
+ global_oplock_break = False;
+
+ /*
+ * If the client did not respond we must die.
+ */
+
+ if(shutdown_server)
+ {
+ DEBUG( 0, ( "oplock_break: client failure in break - " ) );
+ DEBUGADD( 0, ( "shutting down this smbd.\n" ) );
+ close_sockets();
+ close(oplock_sock);
+ exit_server("oplock break failure");
+ }
+
+ if(OPEN_FSP(fsp))
+ {
+ /* The lockingX reply will have removed the oplock flag
+ from the sharemode. */
+ release_file_oplock(fsp);
+ }
+
+ /* Santity check - remove this later. JRA */
+ if(global_oplocks_open < 0)
+ {
+ DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n",
+ global_oplocks_open));
+ exit_server("oplock_break: global_oplocks_open < 0");
+ }
+
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "oplock_break: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Current global_oplocks_open = %d\n", global_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,
+ SMB_DEV_T dev, SMB_INO_T inode)
+{
+ char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+ struct sockaddr_in addr_out;
+ int pid = getpid();
+ time_t start_time;
+ int time_left;
+
+ 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", pid, share_entry->op_port, global_oplock_port));
+ return False;
+ }
+
+ DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+
+ /* Call oplock break direct. */
+ return oplock_break(dev, inode, &share_entry->time);
+ }
+
+ /* We need to send a OPLOCK_BREAK_CMD message to the
+ port in the share mode entry. */
+
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+ SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid);
+ SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec);
+ SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec);
+ SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev);
+ /*
+ * WARNING - beware of SMB_INO_T <> 4 bytes.
+ */
+#ifdef LARGE_SMB_INO_T
+ SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,(inode & 0xFFFFFFFFL));
+ SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET+4,((inode >> 32) & 0xFFFFFFFFL));
+#else /* LARGE_SMB_INO_T */
+ SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode);
+#endif /* LARGE_SMB_INO_T */
+
+ /* set the address and port */
+ bzero((char *)&addr_out,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 ", share_entry->pid, share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ }
+
+ 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 ", share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Error was %s\n", strerror(errno) );
+ }
+ return False;
+ }
+
+ /*
+ * 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];
+ int32 reply_msg_len;
+ uint16 reply_from_port;
+ char *reply_msg_start;
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(oplock_sock,&fds);
+#if defined(HAVE_KERNEL_OPLOCKS)
+ if(lp_kernel_oplocks())
+ FD_SET(oplock_pipe_read,&fds);
+#endif /* HAVE_KERNEL_OPLOCKS */
+
+ 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 ", share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ }
+
+ /*
+ * 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 ", share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Error was (%s).\n", strerror(errno) );
+ }
+ return False;
+ }
+
+ reply_msg_len = IVAL(op_break_reply,OPBRK_CMD_LEN_OFFSET);
+ reply_from_port = SVAL(op_break_reply,OPBRK_CMD_PORT_OFFSET);
+
+ reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN];
+
+
+#if defined(HAVE_KERNEL_OPLOCKS)
+ if((reply_msg_len != OPLOCK_BREAK_MSG_LEN) && (reply_msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN))
+#else
+ if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
+#endif
+ {
+ /* Ignore it. */
+ DEBUG( 0, ( "request_oplock_break: invalid message length (%d) received.", reply_msg_len ) );
+ DEBUGADD( 0, ( " Ignoring.\n" ) );
+ continue;
+ }
+
+ /*
+ * 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 (fsp->open && fsp->granted_oplock && !fsp->sent_oplock_break) {
+
+ /* Try and break the oplock. */
+ file_fd_struct *fd_ptr = fsp->fd_ptr;
+ if(oplock_break( fd_ptr->dev, fd_ptr->inode, &fsp->open_time)) {
+ if(!fsp->open) /* Did the oplock break close the file ? */
+ return True;
+ }
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ Init function to check if kernel level oplocks are available.
+****************************************************************************/
+
+void check_kernel_oplocks(void)
+{
+ static BOOL done;
+
+ /*
+ * We only do this check once on startup.
+ */
+
+ if(done)
+ return;
+
+ done = True;
+ lp_set_kernel_oplocks(False);
+
+#if defined(HAVE_KERNEL_OPLOCKS)
+ {
+ int fd;
+ int pfd[2];
+ pstring tmpname;
+
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY,True);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,True);
+
+ slprintf( tmpname, sizeof(tmpname)-1, "/tmp/ot.%d.XXXXXX", (unsigned int)getpid());
+ mktemp(tmpname);
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n",
+ strerror(errno) ));
+ return;
+ }
+
+ if((fd = open(tmpname, O_RDWR|O_CREAT|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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ oplock_pipe_read = pfd[0];
+ oplock_pipe_write = pfd[1];
+ close(fd);
+
+ DEBUG(3,("check_kernel_oplocks: Kernel oplocks enabled.\n"));
+
+ lp_set_kernel_oplocks(True);
+ }
+#endif /* HAVE_KERNEL_OPLOCKS */
+}
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 87c1fef94c5..f542dbe6089 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,20 +20,19 @@
*/
#include "includes.h"
-#include "loadparm.h"
extern int DEBUGLEVEL;
extern int Protocol;
+BOOL global_machine_pasword_needs_changing;
+
/* 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]="";
+extern pstring scope;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
-#ifdef SMB_PASSWD
/* Data to do lanman1/2 password challenge. */
static unsigned char saved_challenge[8];
static BOOL challenge_sent=False;
@@ -43,24 +42,40 @@ 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;
+#if 0
+ /*
+ * Leave this ifdef'd out while we test
+ * the new crypto random number generator.
+ * JRA.
+ */
+ unsigned char buf[16];
+ static int counter = 0;
+ struct timeval tval;
+ int v1,v2;
+
+ /* get a sort-of random number */
+ GetTimeOfDay(&tval);
+ v1 = (counter++) + getpid() + tval.tv_sec;
+ v2 = (counter++) * getpid() + tval.tv_usec;
+ SIVAL(challenge,0,v1);
+ SIVAL(challenge,4,v2);
+
+ /* mash it up with md4 */
+ mdfour(buf, (unsigned char *)challenge, 8);
+#else
+ unsigned char buf[8];
+
+ generate_random_buffer(buf,8,False);
+#endif
+ memcpy(saved_challenge, buf, 8);
+ memcpy(challenge,buf,8);
+ challenge_sent = True;
}
/*******************************************************************
set the last challenge sent, usually from a password server
********************************************************************/
-BOOL set_challenge(char *challenge)
+BOOL set_challenge(unsigned char *challenge)
{
memcpy(saved_challenge,challenge,8);
challenge_sent = True;
@@ -70,44 +85,29 @@ BOOL set_challenge(char *challenge)
/*******************************************************************
get the last challenge sent
********************************************************************/
-BOOL last_challenge(char *challenge)
+static BOOL last_challenge(unsigned 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);
-}
-
-/****************************************************************************
check if a uid has been validated, and return an pointer to the user_struct
-if it has. NULL if not
+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.
****************************************************************************/
-user_struct *get_valid_user_struct(int uid)
+user_struct *get_valid_user_struct(uint16 vuid)
{
- int vuid = valid_uid(uid);
- if(vuid == -1 || validated_users[vuid].guest)
+ if (vuid == UID_FIELD_INVALID)
+ return NULL;
+ vuid -= VUID_OFFSET;
+ if ((vuid >= (uint16)num_validated_users) ||
+ (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
return NULL;
return &validated_users[vuid];
}
@@ -115,446 +115,219 @@ user_struct *get_valid_user_struct(int uid)
/****************************************************************************
invalidate a uid
****************************************************************************/
-void invalidate_uid(int uid)
+void invalidate_vuid(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 *vuser = get_valid_user_struct(vuid);
+ if (vuser == NULL) return;
-/****************************************************************************
-return a validated username
-****************************************************************************/
-char *validated_username(int vuid)
-{
- return(validated_users[vuid].name);
-}
+ vuser->uid = -1;
+ vuser->gid = -1;
-/****************************************************************************
-register a uid/name pair as being valid and that a valid password
-has been given.
-****************************************************************************/
-void register_uid(int uid,int gid, char *name,BOOL guest)
-{
- user_struct *vuser;
+ vuser->n_sids = 0;
- 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;
- }
-
- vuser = &validated_users[num_validated_users];
- vuser->uid = uid;
- vuser->gid = gid;
- vuser->guest = guest;
- strcpy(vuser->name,name);
+ /* same number of igroups as groups */
+ vuser->n_groups = 0;
- vuser->user_ngroups = 0;
- vuser->user_groups = NULL;
- vuser->user_igroups = NULL;
+ if (vuser->groups) free(vuser->groups);
- /* 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);
+ if (vuser->sids) free(vuser->sids);
- DEBUG(3,("uid %d registered to name %s\n",uid,name));
-
- num_validated_users++;
+ vuser->sids = NULL;
+ vuser->groups = NULL;
}
/****************************************************************************
-add a name to the session users list
+return a validated username
****************************************************************************/
-void add_session_user(char *user)
+char *validated_username(uint16 vuid)
{
- fstring suser;
- StrnCpy(suser,user,sizeof(suser)-1);
-
- if (!Get_Pwnam(suser,True)) return;
-
- 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);
- }
- }
-}
-
-
-#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;
+ user_struct *vuser = get_valid_user_struct(vuid);
+ if (vuser == NULL)
+ return 0;
+ return(vuser->name);
}
-#endif
-#ifdef OSF1_ENH_SEC
/****************************************************************************
-an enhanced crypt for OSF1
+Setup the groups a user belongs to.
****************************************************************************/
-static char *osf1_bigcrypt(char *password,char *salt1)
+int setup_groups(char *user, int uid, int gid, int *p_ngroups, GID_T **p_groups)
{
- 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++;
+ int i,ngroups;
+ GID_T *groups;
+ GID_T grp = 0;
+
+ 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));
+ }
+ }
+ return -1;
+ }
- StrnCpy(salt,salt1,2);
- StrnCpy(result,salt1,2);
+ ngroups = getgroups(0,&grp);
+ if (ngroups <= 0) ngroups = 32;
- 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);
-}
-#endif
+ groups = (GID_T *)malloc(sizeof(groups[0])*ngroups);
+ ngroups = getgroups(ngroups,(gid_t *)groups);
-/****************************************************************************
-update the enhanced security database. Only relevant for OSF1 at the moment.
-****************************************************************************/
-static void update_protected_database( char *user, BOOL result)
-{
-#ifdef OSF1_ENH_SEC
- struct pr_passwd *mypasswd;
- time_t starttime;
- long tz;
+ (*p_ngroups) = ngroups;
- mypasswd = getprpwnam (user);
- starttime = time (NULL);
- tz = mktime ( localtime ( &starttime ) );
+ (*p_groups) = groups;
- 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"));
+ DEBUG( 3, ( "%s is in %d groups: ", user, ngroups ) );
+ for (i = 0; i < ngroups; i++ ) {
+ DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
}
- 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
-}
-
+ DEBUG( 3, ( "\n" ) );
-#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);
+ return 0;
}
-#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)
+/****************************************************************************
+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.
+****************************************************************************/
+uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest)
{
- 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];
+ user_struct *vuser;
+ struct passwd *pwfile; /* for getting real name from passwd file */
+
+ /* Ensure no vuid gets registered in share level security. */
+ if(lp_security() == SEC_SHARE)
+ return UID_FIELD_INVALID;
+#if 0
/*
- * 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!
+ * After observing MS-Exchange services writing to a Samba share
+ * I belive this code is incorrect. Each service does its own
+ * sessionsetup_and_X for the same user, and as each service shuts
+ * down, it does a user_logoff_and_X. As we are consolidating multiple
+ * sessionsetup_and_X's onto the same vuid here, when the first service
+ * shuts down, it invalidates all the open files for the other services.
+ * Hence I am removing this code and forcing each sessionsetup_and_X
+ * to get a new vuid.
+ * Jeremy Allison. (jallison@whistle.com).
*/
- if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
- dcelogin_atmost_once)
- return(False);
+ int i;
+ for(i = 0; i < num_validated_users; i++) {
+ vuser = &validated_users[i];
+ if ( vuser->uid == uid )
+ return (uint16)(i + VUID_OFFSET); /* User already validated */
+ }
+#endif
- if (sec_login_setup_identity(
- (unsigned char *)this_user,
- sec_login_no_flags,
- &my_dce_sec_context,
- &err) == 0)
+ validated_users = (user_struct *)Realloc(validated_users,
+ sizeof(user_struct)*
+ (num_validated_users+1));
+
+ if (!validated_users)
{
- dce_error_inq_text(err, dce_errstr, &err2);
- DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
- this_user,dce_errstr));
- return(False);
+ DEBUG(0,("Failed to realloc users struct!\n"));
+ num_validated_users = 0;
+ return UID_FIELD_INVALID;
}
- 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);
- }
+ vuser = &validated_users[num_validated_users];
+ num_validated_users++;
- 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()));
- }
+ vuser->uid = uid;
+ vuser->gid = gid;
+ vuser->guest = guest;
+ fstrcpy(vuser->name,unix_name);
+ fstrcpy(vuser->requested_name,requested_name);
- dcelogin_atmost_once = 1;
- return (True);
-}
+ vuser->n_sids = 0;
+ vuser->sids = NULL;
-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));
- }
-}
+ vuser->n_groups = 0;
+ vuser->groups = NULL;
-#endif
+ /* Find all the groups this uid is in and store them.
+ Used by become_user() */
+ setup_groups(unix_name,uid,gid,
+ &vuser->n_groups,
+ &vuser->groups);
+ DEBUG(3,("uid %d registered to name %s\n",uid,unix_name));
-#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);
+ DEBUG(3, ("Clearing default real name\n"));
+ fstrcpy(vuser->real_name, "<Full Name>\0");
+ if (lp_unix_realname()) {
+ if ((pwfile=getpwnam(vuser->name))!= NULL)
+ {
+ DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
+ fstrcpy(vuser->real_name, pwfile->pw_gecos);
+ }
}
-
- return(1);
+
+ return (uint16)((num_validated_users - 1) + VUID_OFFSET);
}
-#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
+add a name to the session users list
****************************************************************************/
-static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
+void add_session_user(char *user)
{
- int len = strlen(s);
- int i;
-
-#ifdef PASSWORD_LENGTH
- len = MIN(len,PASSWORD_LENGTH);
-#endif
+ fstring suser;
+ StrnCpy(suser,user,sizeof(suser)-1);
- if (N <= 0 || offset >= len)
- return(fn(s));
+ if (!Get_Pwnam(suser,True)) return;
- 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;
+ 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
+ {
+ pstrcat(session_users," ");
+ pstrcat(session_users,suser);
+ }
}
- return(False);
-}
-
-/****************************************************************************
-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);
}
-
/****************************************************************************
-core of password checking routine
-****************************************************************************/
-BOOL password_check(char *password)
+update the encrypted smbpasswd file from the plaintext username and password
+*****************************************************************************/
+static BOOL update_smbpassword_file(char *user, char *password)
{
-#ifdef AFS_AUTH
- if (afs_auth(this_user,password)) return(True);
-#endif
-
-#ifdef DFS_AUTH
- if (dfs_auth(this_user,password)) return(True);
-#endif
+ struct smb_passwd *smbpw;
+ BOOL ret;
+
+ become_root(0);
+ smbpw = getsmbpwnam(user);
+ unbecome_root(0);
+
+ if(smbpw == NULL) {
+ DEBUG(0,("getsmbpwnam returned NULL\n"));
+ return False;
+ }
+
+ /* Here, the flag is one, because we want to ignore the
+ XXXXXXX'd out password */
+ ret = change_oem_password( smbpw, password, True);
+ if (ret == False) {
+ DEBUG(3,("change_oem_password returned False\n"));
+ }
-#ifdef PWDAUTH
- if (pwdauth(this_user,password) == 0)
- return(True);
-#endif
+ return ret;
+}
-#ifdef OSF1_ENH_SEC
- return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
-#endif
-#ifdef ULTRIX_AUTH
- return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
-#endif
-#ifdef LINUX_BIGCRYPT
- return(linux_bigcrypt(password,this_salt,this_crypted));
-#endif
-#ifdef NO_CRYPT
- DEBUG(1,("Warning - no crypt available\n"));
- return(False);
-#else
- return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
-#endif
-}
-#ifdef SMB_PASSWD
/****************************************************************************
core of smb password checking routine.
****************************************************************************/
@@ -564,10 +337,10 @@ BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned cha
unsigned char p21[21];
unsigned char p24[24];
- if(part_passwd == NULL)
+ if (part_passwd == NULL)
DEBUG(10,("No password set - allowing access\n"));
/* No password set - always true ! */
- if(part_passwd == NULL)
+ if (part_passwd == NULL)
return 1;
memset(p21,'\0',21);
@@ -596,282 +369,180 @@ BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned cha
#endif
return (memcmp(p24, password, 24) == 0);
}
-#endif
/****************************************************************************
-check if a username/password is OK
+ Do a specific test for an smb password being correct, given a smb_password and
+ the lanman and NT responses.
****************************************************************************/
-BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password)
+BOOL smb_password_ok(struct smb_passwd *smb_pass,
+ uchar lm_pass[24], uchar nt_pass[24])
{
- 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
+ uchar challenge[8];
- if (password) password[pwlen] = 0;
+ if (!lm_pass || !smb_pass) return(False);
-#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);
-
-#ifdef SMB_PASSWD
-
- DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
-
- 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(smb_pass->acct_ctrl & ACB_DISABLED) {
+ DEBUG(3,("account for user %s was disabled.\n",
+ smb_pass->smb_name));
+ return(False);
}
- smb_pass = get_smbpwnam(user);
- if(!smb_pass)
- {
- DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
- return(False);
+ if (!last_challenge(challenge)) {
+ DEBUG(1,("no challenge done - password failed\n"));
+ return False;
}
- /* 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);
- }
+ DEBUG(4,("Checking SMB password for user %s\n",
+ smb_pass->smb_name));
- if(Protocol >= PROTOCOL_NT1 && is_nt_password)
- {
+ if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) {
/* 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);
+ DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
+ if (smb_password_check((char *)nt_pass,
+ (uchar *)smb_pass->smb_nt_passwd,
+ challenge)) {
+ DEBUG(4,("NT MD4 password check succeeded\n"));
+ return(True);
}
+ DEBUG(4,("NT MD4 password check failed\n"));
}
- /* Try against the lanman password */
-
- if(smb_password_check(password, smb_pass->smb_passwd, challenge))
- {
- update_protected_database(user,True);
- return(True);
- }
-
- DEBUG(3,("Error smb_password_check failed\n"));
- }
-#endif
+ /* Try against the lanman password. smb_pass->smb_passwd == NULL means
+ no password, allow access. */
- DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
-
- if (!pass)
- {
- DEBUG(3,("Couldn't find user %s\n",user));
- return(False);
- }
+ DEBUG(4,("Checking LM MD4 password\n"));
-#ifdef SHADOW_PWD
- {
- struct spwd *spass;
+ if((smb_pass->smb_passwd == NULL) &&
+ (smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
+ DEBUG(4,("no password required for user %s\n",
+ smb_pass->smb_name));
+ return True;
+ }
- /* 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 */
+ if((smb_pass->smb_passwd != NULL) &&
+ smb_password_check((char *)lm_pass,
+ (uchar *)smb_pass->smb_passwd, challenge)) {
+ DEBUG(4,("LM MD4 password check succeeded\n"));
+ return(True);
+ }
- spass = getspnam(pass->pw_name);
- if (spass && spass->sp_pwdp)
- pass->pw_passwd = spass->sp_pwdp;
- }
-#endif
+ DEBUG(4,("LM MD4 password check failed\n"));
-#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
-
-#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
+ return False;
+}
-#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
+/****************************************************************************
+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 BOOL pass_check_smb(char *user,char *password, struct passwd *pwd)
+{
+ struct passwd *pass;
+ uchar challenge[8];
+ struct smb_passwd *smb_pass;
+ BOOL challenge_done;
- /* 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
- }
+ if (!password) {
+ return(False);
+ }
- /* try it as it came to us */
- if (password_check(password))
- {
- update_protected_database(user,True);
- return(True);
- }
+ challenge_done = last_challenge(challenge);
- /* 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);
+ if (!challenge_done) {
+ DEBUG(0,("Error: challenge not done for user=%s\n", user));
+ 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 (pwd && !user) {
+ pass = (struct passwd *) pwd;
+ user = pass->pw_name;
+ } else {
+ pass = Get_Pwnam(user,True);
+ }
- /* give up? */
- if(level < 1)
- {
- update_protected_database(user,False);
+ if (!pass) {
+ DEBUG(3,("Couldn't find user %s\n",user));
+ return(False);
+ }
- /* restore it */
- strcpy(password,pass2);
+ smb_pass = getsmbpwnam(user);
- return(False);
- }
+ if (!smb_pass) {
+ DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
+ return(False);
+ }
- /* last chance - all combinations of up to level chars upper! */
- strlower(password);
+ /* Quit if the account was disabled. */
+ if(smb_pass->acct_ctrl & ACB_DISABLED) {
+ DEBUG(3,("account for user %s was disabled.\n", user));
+ return(False);
+ }
- if (string_combinations(password,password_check,level))
- {
- update_protected_database(user,True);
- return(True);
- }
+ /* 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);
+ }
- update_protected_database(user,False);
-
- /* restore it */
- strcpy(password,pass2);
-
- return(False);
+ if (smb_password_ok(smb_pass,
+ (unsigned char *)password,
+ (uchar *)password)) {
+ return(True);
+ }
+
+ DEBUG(3,("Error smb_password_check failed\n"));
+ return False;
}
-
+/****************************************************************************
+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 *user,char *password, int pwlen, struct passwd *pwd)
+{
+ if (pwlen == 24) {
+ /* if it is 24 bytes long then assume it is an encrypted
+ password */
+ return pass_check_smb(user, password, pwd);
+ }
+
+ return pass_check(user, password, pwlen, pwd,
+ lp_update_encrypted() ?
+ update_smbpassword_file : NULL);
+}
/****************************************************************************
check if a username is valid
****************************************************************************/
BOOL user_ok(char *user,int snum)
{
- 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);
+ 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);
- }
+ 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);
+ return(ret);
}
@@ -882,14 +553,14 @@ validate a group username entry. Return the username or NULL
****************************************************************************/
static char *validate_group(char *group,char *password,int pwlen,int snum)
{
-#ifdef NETGROUP
+#ifdef HAVE_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)) {
+ password_ok(user,password,pwlen,NULL)) {
endnetgrent();
return(user);
}
@@ -899,7 +570,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
}
#endif
-#if HAVE_GETGRNAM
+#ifdef HAVE_GETGRNAM
{
struct group *gptr = (struct group *)getgrnam(group);
char **member;
@@ -909,9 +580,9 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
while (member && *member)
{
static fstring name;
- strcpy(name,*member);
+ fstrcpy(name,*member);
if (user_ok(name,snum) &&
- password_ok(name,password,pwlen,NULL,False))
+ password_ok(name,password,pwlen,NULL))
return(&name[0]);
member++;
}
@@ -924,8 +595,8 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
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);
+ if (password_ok(NULL, password, pwlen, pwd)) {
+ fstrcpy(tm, pwd->pw_name);
endpwent ();
return tm;
}
@@ -946,7 +617,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
check for authority to login to a service with a given username/password
****************************************************************************/
BOOL authorise_login(int snum,char *user,char *password, int pwlen,
- BOOL *guest,BOOL *force,int vuid)
+ BOOL *guest,BOOL *force,uint16 vuid)
{
BOOL ok = False;
@@ -956,7 +627,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
#endif
- /* there are several possabilities:
+ /* 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
@@ -973,18 +644,20 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
{
+ user_struct *vuser = get_valid_user_struct(vuid);
+
/* check the given username and password */
if (!ok && (*user) && user_ok(user,snum)) {
- ok = password_ok(user,password, pwlen, NULL, False);
+ ok = password_ok(user,password, pwlen, NULL);
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;
+ if (!ok && (vuser != 0) && vuser->guest) {
+ if (user_ok(vuser->name,snum) &&
+ password_ok(vuser->name, password, pwlen, NULL)) {
+ fstrcpy(user, vuser->name);
+ vuser->guest = False;
DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
ok = True;
}
@@ -992,38 +665,38 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
/* now check the list of session users */
- if (!ok)
- {
- char *auser;
- char *user_list = strdup(session_users);
- if (!user_list) return(False);
+ 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;
+ 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, pwlen, NULL, False)) {
- ok = True;
- strcpy(user,user2);
- DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
- }
- }
- free(user_list);
- }
-
- /* 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;
+ if (password_ok(user2,password, pwlen, NULL)) {
+ ok = True;
+ fstrcpy(user,user2);
+ DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
+ }
}
+ free(user_list);
+ }
+
+ /* check for a previously validated username/password pair */
+ if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
+ (vuser != 0) && !vuser->guest &&
+ user_ok(vuser->name,snum)) {
+ fstrcpy(user,vuser->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)) {
@@ -1049,19 +722,19 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
if (auser)
{
ok = True;
- strcpy(user,auser);
+ fstrcpy(user,auser);
DEBUG(3,("ACCEPTED: group username and given password ok\n"));
}
}
else
{
fstring user2;
- strcpy(user2,auser);
+ fstrcpy(user2,auser);
if (user_ok(user2,snum) &&
- password_ok(user2,password,pwlen,NULL, False))
+ password_ok(user2,password,pwlen,NULL))
{
ok = True;
- strcpy(user,user2);
+ fstrcpy(user,user2);
DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
}
}
@@ -1076,7 +749,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
if (Get_Pwnam(guestname,True))
{
- strcpy(user,guestname);
+ fstrcpy(user,guestname);
ok = True;
DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
}
@@ -1147,25 +820,25 @@ static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
}
file_host = strtok(bp, " \t\n");
file_user = strtok(NULL, " \t\n");
- DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
+ 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;
-#ifdef NETGROUP
- /* THIS IS UNTESTED!! */
+#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(remote,file_host,user,mydomain))
+ if (mydomain && innetgr(file_host,remote,user,mydomain))
host_ok = True;
}
#else
if (is_group)
{
- DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
+ DEBUG(1,("Netgroups not configured\n"));
continue;
}
#endif
@@ -1210,207 +883,492 @@ BOOL check_hosts_equiv(char *user)
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 (fname && *fname && (pass->pw_uid != 0)) {
+ extern int Client;
+ if (check_user_equiv(user,client_name(Client),fname))
+ return(True);
+ }
if (lp_use_rhosts())
{
char *home = get_home_dir(user);
- if (home)
- {
- sprintf(rhostsfile, "%s/.rhosts", home);
- if (check_user_equiv(user,Client_info.name,rhostsfile))
- return(True);
- }
+ if (home) {
+ extern int Client;
+ slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
+ if (check_user_equiv(user,client_name(Client),rhostsfile))
+ return(True);
+ }
}
return(False);
}
-static int password_client = -1;
-static fstring pserver;
+static struct cli_state pw_cli;
/****************************************************************************
-attempted support for server level security
+return the client state structure
****************************************************************************/
-BOOL server_cryptkey(char *buf)
+struct cli_state *server_client(void)
{
- 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;
+ return &pw_cli;
+}
- if (password_client >= 0)
- close(password_client);
- password_client = -1;
+/****************************************************************************
+support for server level security
+****************************************************************************/
+struct cli_state *server_cryptkey(void)
+{
+ fstring desthost;
+ struct in_addr dest_ip;
+ extern fstring local_machine;
+ char *p;
+ BOOL connected_ok = False;
+ struct nmb_name calling, called;
+
+ if (!cli_initialise(&pw_cli))
+ return NULL;
+
+ p = lp_passwordserver();
+ while(p && next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
+ standard_sub_basic(desthost);
+ strupper(desthost);
+
+ if(!resolve_name( desthost, &dest_ip)) {
+ 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 (Protocol < PROTOCOL_NT1) {
- strcpy(pass_protocol,"LM1.2X002");
- } else {
- strcpy(pass_protocol,"NT LM 0.12");
- }
+ if (cli_connect(&pw_cli, desthost, &dest_ip)) {
+ DEBUG(3,("connected to password server %s\n",desthost));
+ connected_ok = True;
+ break;
+ }
+ }
- bzero(inbuf,sizeof(inbuf));
- bzero(outbuf,sizeof(outbuf));
+ if (!connected_ok) {
+ DEBUG(0,("password server not available\n"));
+ cli_shutdown(&pw_cli);
+ return NULL;
+ }
- for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
- strcpy(desthost,p);
- standard_sub_basic(desthost);
- strupper(desthost);
+ make_nmb_name(&calling, local_machine, 0x0 , scope);
+ make_nmb_name(&called , desthost , 0x20, scope);
- dest_ip = *interpret_addr2(desthost);
- if (zero_ip(dest_ip)) {
- DEBUG(1,("Can't resolve address for %s\n",p));
- continue;
- }
+ if (!cli_session_request(&pw_cli, &calling, &called))
+ {
+ DEBUG(1,("%s rejected the session\n",desthost));
+ cli_shutdown(&pw_cli);
+ return NULL;
+ }
- if (memcmp(&dest_ip,&myip,sizeof(dest_ip)) == 0) {
- DEBUG(1,("Password server loop - disabling password server %s\n",p));
- continue;
- }
+ DEBUG(3,("got session\n"));
- 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 (!cli_negprot(&pw_cli)) {
+ DEBUG(1,("%s rejected the negprot\n",desthost));
+ cli_shutdown(&pw_cli);
+ return NULL;
+ }
- if (password_client < 0) {
- DEBUG(1,("password server not available\n"));
- return(False);
- }
+ if (pw_cli.protocol < PROTOCOL_LANMAN2 ||
+ !(pw_cli.sec_mode & 1)) {
+ DEBUG(1,("%s isn't in user level security mode\n",desthost));
+ cli_shutdown(&pw_cli);
+ return NULL;
+ }
+ DEBUG(3,("password server OK\n"));
- /* send a session request (RFC 8002) */
+ return &pw_cli;
+}
- /* put in the destination name */
- len = 4;
- p = outbuf+len;
- name_mangle(desthost,p,' ');
- len += name_len(p);
+/****************************************************************************
+validate a password with the password server
+****************************************************************************/
+BOOL server_validate(char *user, char *domain,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen)
+{
+ extern fstring local_machine;
+ static unsigned char badpass[24];
+
+ if (!pw_cli.initialised) {
+ DEBUG(1,("password server %s is not connected\n", pw_cli.desthost));
+ return(False);
+ }
+
+ if(badpass[0] == 0) {
+ memset(badpass, 0x1f, sizeof(badpass));
+ }
+
+ if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
+ /* Very unlikely, our random bad password is the same as the users
+ password. */
+ memset(badpass, badpass[0]+1, sizeof(badpass));
+ }
+
+ /*
+ * 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.
+ */
+
+ if (cli_session_setup(&pw_cli, user, (char *)badpass, sizeof(badpass),
+ (char *)badpass, sizeof(badpass), domain)) {
+ if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) == 0) {
+ DEBUG(0,("server_validate: password server %s allows users as non-guest \
+with a bad password.\n", pw_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(&pw_cli);
+ return False;
+ }
+ cli_ulogoff(&pw_cli);
+ }
+
+ /*
+ * 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 (!cli_session_setup(&pw_cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
+ DEBUG(1,("password server %s rejected the password\n", pw_cli.desthost));
+ return False;
+ }
- /* and my name */
- p = outbuf+len;
- name_mangle(remote_machine,p,' ');
- len += name_len(p);
+ /* if logged in as guest then reject */
+ if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) != 0) {
+ DEBUG(1,("password server %s gave us guest only\n", pw_cli.desthost));
+ cli_ulogoff(&pw_cli);
+ return(False);
+ }
- _smb_setlen(outbuf,len);
- CVAL(outbuf,0) = 0x81;
+ /*
+ * This patch from Rob Nielsen <ran@adc.com> makes doing
+ * the NetWksaUserLogon a dynamic, rather than compile-time
+ * parameter, defaulting to on. This is somewhat dangerous
+ * as it allows people to turn off this neccessary check,
+ * but so many people have had problems with this that I
+ * think it is a neccessary change. JRA.
+ */
+
+ if (lp_net_wksta_user_logon()) {
+ DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
+
+ if (!cli_send_tconX(&pw_cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("password server %s refused IPC$ connect\n", pw_cli.desthost));
+ cli_ulogoff(&pw_cli);
+ return False;
+ }
+
+ if (!cli_NetWkstaUserLogon(&pw_cli,user,local_machine)) {
+ DEBUG(0,("password server %s failed NetWkstaUserLogon\n", pw_cli.desthost));
+ cli_tdis(&pw_cli);
+ cli_ulogoff(&pw_cli);
+ return False;
+ }
- send_smb(password_client,outbuf);
- receive_smb(password_client,inbuf,5000);
-
- if (CVAL(inbuf,0) != 0x82) {
- DEBUG(1,("%s rejected the session\n",pserver));
- close(password_client); password_client = -1;
- return(False);
+ if (pw_cli.privilages == 0) {
+ DEBUG(0,("password server %s gave guest privilages\n", pw_cli.desthost));
+ cli_tdis(&pw_cli);
+ cli_ulogoff(&pw_cli);
+ return False;
+ }
+
+ if (!strequal(pw_cli.eff_name, user)) {
+ DEBUG(0,("password server %s gave different username %s\n",
+ pw_cli.desthost,
+ pw_cli.eff_name));
+ cli_tdis(&pw_cli);
+ cli_ulogoff(&pw_cli);
+ return False;
+ }
+ cli_tdis(&pw_cli);
+ }
+ else {
+ DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
+ }
+
+ DEBUG(3,("password server %s accepted the password\n", pw_cli.desthost));
+
+ cli_ulogoff(&pw_cli);
+
+ return(True);
+}
+
+/***********************************************************************
+ Do the same as security=server, but using NT Domain calls and a session
+ key from the machine password.
+************************************************************************/
+
+BOOL domain_client_validate( char *user, char *domain,
+ char *smb_apasswd, int smb_apasslen,
+ char *smb_ntpasswd, int smb_ntpasslen)
+{
+ unsigned char local_challenge[8];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_reponse[24];
+ unsigned char trust_passwd[16];
+ time_t lct;
+ fstring remote_machine;
+ char *p;
+ struct in_addr dest_ip;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 info3;
+ struct cli_state cli;
+ uint32 smb_uid_low;
+ BOOL connected_ok = False;
+ struct nmb_name calling, called;
+
+ /*
+ * 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(strequal( domain, global_myname)) {
+ DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
+ return False;
}
- DEBUG(3,("got session\n"));
+ /*
+ * Next, check that the passwords given were encrypted.
+ */
- bzero(outbuf,smb_size);
+ if(((smb_apasslen != 24) && (smb_apasslen != 0)) ||
+ ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
+ generate_random_buffer( local_challenge, 8, False);
+ SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
+ SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
+ smb_apasslen = 24;
+ smb_ntpasslen = 24;
+ smb_apasswd = (char *)local_lm_response;
+ smb_ntpasswd = (char *)local_nt_reponse;
+ } else {
- /* setup the protocol string */
- set_message(outbuf,0,strlen(pass_protocol)+2,True);
- p = smb_buf(outbuf);
- *p++ = 2;
- strcpy(p,pass_protocol);
+ /*
+ * Encrypted - get the challenge we sent for these
+ * responses.
+ */
- CVAL(outbuf,smb_com) = SMBnegprot;
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
+ if (!last_challenge(local_challenge)) {
+ DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
+ return False;
+ }
+ }
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
+ /*
+ * Get the machine account password.
+ */
+ if(!trust_password_lock( global_myworkgroup, global_myname, False)) {
+ DEBUG(0,("domain_client_validate: unable to open the machine account password file for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+ return False;
+ }
- 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(get_trust_account_password( trust_passwd, &lct) == False) {
+ DEBUG(0,("domain_client_validate: unable to read the machine account password for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+ trust_password_unlock();
+ 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);
+ trust_password_unlock();
+
+ /*
+ * Here we check the last change time to see if the machine
+ * password needs changing. JRA.
+ */
+
+ if(time(NULL) > lct + lp_machine_password_timeout())
+ global_machine_pasword_needs_changing = True;
+
+ /*
+ * 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);
+
+ if(cli_initialise(&cli) == False) {
+ DEBUG(0,("domain_client_validate: unable to initialize client connection.\n"));
+ return False;
}
- memcpy(buf,inbuf,smb_len(inbuf)+4);
+ /*
+ * Treat each name in the 'password server =' line as a potential
+ * PDC/BDC. Contact each in turn and try and authenticate.
+ */
- DEBUG(3,("password server OK\n"));
+ p = lp_passwordserver();
+ while(p && next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
- return(True);
-}
+ standard_sub_basic(remote_machine);
+ strupper(remote_machine);
+
+ if(!resolve_name( remote_machine, &dest_ip)) {
+ DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
+ continue;
+ }
+
+ if (ismyip(dest_ip)) {
+ DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
+ continue;
+ }
+
+ if (!cli_connect(&cli, remote_machine, &dest_ip)) {
+ DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ continue;
+ }
+
+ make_nmb_name(&calling, global_myname , 0x0 , scope);
+ make_nmb_name(&called , remote_machine, 0x20, scope);
-/****************************************************************************
-attempted support for server level security
-****************************************************************************/
-BOOL server_validate(char *buf)
-{
- pstring inbuf,outbuf;
- BOOL ret;
+ if (!cli_session_request(&pw_cli, &calling, &called))
+ {
+ DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ continue;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
- if (password_client < 0) {
- DEBUG(1,("%s not connected\n",pserver));
- return(False);
- }
+ if (!cli_negprot(&cli)) {
+ DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ continue;
+ }
+
+ if (cli.protocol != PROTOCOL_NT1) {
+ DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ cli_shutdown(&cli);
+ continue;
+ }
- bzero(inbuf,sizeof(inbuf));
- memcpy(outbuf,buf,sizeof(outbuf));
+ /*
+ * Do an anonymous session setup.
+ */
- /* send a session setup command */
- CVAL(outbuf,smb_flg) = 0x8;
- SSVAL(outbuf,smb_flg2,0x1);
- CVAL(outbuf,smb_vwv0) = 0xFF;
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ continue;
+ }
- set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
+ if (!(cli.sec_mode & 1)) {
+ DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
+ remote_machine));
+ cli_shutdown(&cli);
+ continue;
+ }
- SCVAL(inbuf,smb_rcls,1);
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ cli_shutdown(&cli);
+ continue;
+ }
- send_smb(password_client,outbuf);
- ret = receive_smb(password_client,inbuf,5000);
+ /*
+ * We have an anonymous connection to IPC$.
+ */
+ connected_ok = True;
+ break;
+ }
- if (!ret || CVAL(inbuf,smb_rcls) != 0) {
- DEBUG(1,("password server %s rejected the password\n",pserver));
- return(False);
+ if (!connected_ok) {
+ DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
+ cli_shutdown(&cli);
+ return False;
}
- /* 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);
+ /*
+ * 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) == False) {
+ DEBUG(0,("domain_client_validate: 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;
}
- DEBUG(3,("password server %s accepted the password\n",pserver));
+ if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
+ DEBUG(0,("domain_client_validate: unable to setup the PDC credentials 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;
+ }
-#ifndef KEEP_PASSWORD_SERVER_OPEN
- close(password_client); password_client= -1;
-#endif
+ /* We really don't care what LUID we give the user. */
+ generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
+
+ if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
+ ((smb_apasslen != 0) ? smb_apasswd : NULL),
+ ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
+ &ctr, &info3) == False) {
+ DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
+%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
- return(True);
-}
+ /*
+ * Here, if we really want it, we have lots of info about the user in info3.
+ */
+
+#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(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)));
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return False;
+ }
+#endif /* 0 */
+ cli_nt_session_close(&cli);
+ cli_ulogoff(&cli);
+ cli_shutdown(&cli);
+ return True;
+}
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
new file mode 100644
index 00000000000..15d395b29a3
--- /dev/null
+++ b/source/smbd/pipes.c
@@ -0,0 +1,158 @@
+/*
+ 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"
+#include "trans2.h"
+
+#define PIPE "\\PIPE\\"
+#define PIPELEN strlen(PIPE)
+
+extern int DEBUGLEVEL;
+
+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;
+ 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 */
+ pstrcpy(fname,smb_buf(inbuf));
+
+ /* 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(fname,PIPE,PIPELEN) != 0 )
+ return(ERROR(ERRSRV,ERRaccess));
+
+ DEBUG(4,("Opening pipe %s.\n", fname));
+
+ /* See if it is one we want to handle. */
+ for( i = 0; pipe_names[i].client_pipe ; i++ )
+ if( strequal(fname,pipe_names[i].client_pipe) )
+ break;
+
+ if (pipe_names[i].client_pipe == NULL)
+ return(ERROR(ERRSRV,ERRaccess));
+
+ /* Strip \PIPE\ off the name. */
+ pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
+
+ /* 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 |= 0x10; /* Add Create it not exists flag */
+
+ p = open_rpc_pipe_p(fname, conn, vuid);
+ if (!p) return(ERROR(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,0);
+
+ 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);
+ uint32 smb_offs = IVAL(inbuf,smb_vwv3);
+ int smb_maxcnt = SVAL(inbuf,smb_vwv5);
+ int smb_mincnt = SVAL(inbuf,smb_vwv6);
+ int nread = -1;
+ char *data;
+
+ if (!p) return(ERROR(ERRDOS,ERRbadfid));
+
+ set_message(outbuf,12,0,True);
+ data = smb_buf(outbuf);
+
+ nread = read_pipe(p, data, smb_offs, 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 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(ERRDOS,ERRbadfid));
+
+ DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum));
+
+ if (!close_rpc_pipe_hnd(p, conn)) return(ERROR(ERRDOS,ERRbadfid));
+
+ return(outsize);
+}
+
diff --git a/source/smbd/predict.c b/source/smbd/predict.c
new file mode 100644
index 00000000000..5f015139cf3
--- /dev/null
+++ b/source/smbd/predict.c
@@ -0,0 +1,162 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ file read prediction 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"
+
+extern int DEBUGLEVEL;
+
+#if USE_READ_PREDICTION
+
+/* variables used by the read prediction module */
+static int rp_fd = -1;
+static SMB_OFF_T rp_offset = 0;
+static ssize_t rp_length = 0;
+static ssize_t rp_alloced = 0;
+static int rp_predict_fd = -1;
+static SMB_OFF_T rp_predict_offset = 0;
+static size_t rp_predict_length = 0;
+static int rp_timeout = 5;
+static time_t rp_time = 0;
+static char *rp_buffer = NULL;
+static BOOL predict_skip=False;
+extern time_t smb_last_time;
+
+/****************************************************************************
+handle read prediction on a file
+****************************************************************************/
+ssize_t read_predict(int fd,SMB_OFF_T offset,char *buf,char **ptr,size_t num)
+{
+ ssize_t ret = 0;
+ ssize_t 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 {
+ SMB_STRUCT_STAT rp_stat;
+
+ /* Find the end of the file - ensure we don't
+ read predict beyond it. */
+ if(sys_fstat(fd,&rp_stat) < 0)
+ {
+ DEBUG(0,("read-prediction failed on fstat. Error was %s\n", strerror(errno)));
+ predict_skip = True;
+ }
+ else
+ {
+ predict_skip = False;
+
+ /* prepare the next prediction */
+ rp_predict_fd = fd;
+ /* Make sure we don't seek beyond the end of the file. */
+ rp_predict_offset = MIN((offset + num),rp_stat.st_size);
+ rp_predict_length = num;
+ }
+ }
+
+ if (ret < 0) ret = 0;
+
+ return(ret);
+}
+
+/****************************************************************************
+pre-read some data
+****************************************************************************/
+void do_read_prediction(void)
+{
+ static size_t readsize = 0;
+
+ 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;
+
+ if (readsize == 0) {
+ readsize = lp_readsize();
+ readsize = MAX(readsize,1024);
+ }
+
+ 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 (sys_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)
+{
+ if (rp_fd == fd)
+ rp_fd = -1;
+ if (rp_predict_fd == fd)
+ rp_predict_fd = -1;
+}
+
+#else
+ void read_prediction_dummy(void) ;
+#endif
diff --git a/source/smbd/process.c b/source/smbd/process.c
new file mode 100644
index 00000000000..656e2e99e12
--- /dev/null
+++ b/source/smbd/process.c
@@ -0,0 +1,940 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+time_t smb_last_time=(time_t)0;
+
+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 pstring sesssetup_user;
+extern char *last_inbuf;
+extern char *InBuffer;
+extern char *OutBuffer;
+extern int smb_read_error;
+extern BOOL reload_after_sighup;
+extern BOOL global_machine_pasword_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"));
+ free((char *)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 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) return this first.
+
+ 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, BOOL *got_smb)
+{
+ extern int Client;
+ fd_set fds;
+ int selrtn;
+ struct timeval to;
+ int maxfd;
+
+ smb_read_error = 0;
+
+ *got_smb = False;
+
+ /*
+ * 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. */
+ free((char *)msg->msg_buf);
+ free((char *)msg);
+ *got_smb = True;
+
+ DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
+ return True;
+ }
+
+ /*
+ * Setup the select read fd set.
+ */
+
+ FD_ZERO(&fds);
+ FD_SET(Client,&fds);
+ maxfd = setup_oplock_select_set(&fds);
+
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
+
+ selrtn = sys_select(MAX(maxfd,Client)+1,&fds,timeout>0?&to:NULL);
+
+ /* 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 (FD_ISSET(Client,&fds))
+ {
+ *got_smb = True;
+ return receive_smb(Client, buffer, 0);
+ }
+ else
+ {
+ return receive_local_message(&fds, buffer, buffer_len, 0);
+ }
+}
+
+/****************************************************************************
+Get the next SMB packet, doing the local message processing automatically.
+****************************************************************************/
+
+BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
+{
+ BOOL got_smb = False;
+ BOOL ret;
+
+ do
+ {
+ ret = receive_message_or_smb(inbuf,bufsize,timeout,&got_smb);
+
+ if(ret && !got_smb)
+ {
+ /* Deal with oplock break requests from other smbd's. */
+ process_local_message(inbuf, bufsize);
+ continue;
+ }
+
+ if(ret && (CVAL(inbuf,0) == 0x85))
+ {
+ /* Keepalive packet. */
+ got_smb = False;
+ }
+
+ }
+ while(ret && !got_smb);
+
+ return ret;
+}
+
+
+/*
+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!
+*/
+struct smb_message_struct
+{
+ int code;
+ char *name;
+ int (*fn)(connection_struct *conn, char *, char *, int, int);
+ int flags;
+}
+ 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}, /* ulogoff doesn't give a valid TID */
+ {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 | QUEUE_IN_OPLOCK },
+
+ /* 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 | QUEUE_IN_OPLOCK},
+ {SMBread,"SMBread",reply_read,AS_USER},
+ {SMBwrite,"SMBwrite",reply_write,AS_USER},
+ {SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC},
+ {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 | QUEUE_IN_OPLOCK},
+
+ /* 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 | QUEUE_IN_OPLOCK },
+ {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
+ {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 | QUEUE_IN_OPLOCK },
+ {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+
+ {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+ {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
+ {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},
+
+ /* NT PROTOCOL FOLLOWS */
+ {SMBntcreateX, "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
+ {SMBnttrans, "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
+ {SMBnttranss, "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
+ {SMBntcancel, "SMBntcancel", reply_ntcancel, 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}
+ };
+
+
+/****************************************************************************
+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;
+ extern int Client;
+
+ 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(global_oplock_break && (smb_messages[match].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;
+ }
+
+ if (smb_messages[match].fn)
+ {
+ int flags = smb_messages[match].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));
+
+
+ /* Ensure this value is replaced in the incoming packet. */
+ SSVAL(inbuf,smb_uid,session_tag);
+
+ /*
+ * Ensure the correct username is in sesssetup_user.
+ * 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)
+ pstrcpy( sesssetup_user, vuser->requested_name);
+ }
+
+ /* 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(conn,session_tag)) {
+ if (flags & AS_GUEST)
+ flags &= ~AS_USER;
+ else
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
+ /* 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(ERRSRV,ERRaccess));
+
+ /* ipc services are limited */
+ if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) {
+ return(ERROR(ERRSRV,ERRaccess));
+ }
+
+ /* load service specific parameters */
+ if (conn &&
+ !become_service(conn,(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(Client, lp_hostsallow(-1), lp_hostsdeny(-1)))) {
+ return(ERROR(ERRSRV,ERRaccess));
+ }
+
+ last_inbuf = inbuf;
+
+ outsize = smb_messages[match].fn(conn, inbuf,outbuf,size,bufsize);
+ }
+ else
+ {
+ outsize = reply_unknown(inbuf,outbuf);
+ }
+ }
+
+ 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);
+ extern int chain_size;
+
+ smb_last_time = time(NULL);
+
+ 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);
+}
+
+
+/****************************************************************************
+ 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)
+{
+ extern int Client;
+#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;
+
+ 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 (!check_access(Client, lp_hostsallow(-1), lp_hostsdeny(-1))) {
+ /* send a negative session response "not listining on calling
+ name" */
+ static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+ DEBUG( 1, ( "Connection denied from %s\n",
+ client_addr(Client) ) );
+ send_smb(Client,(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(Client, msg_type);
+ if(sslConnected < 0){ /* an error occured */
+ exit_server("SSL negotiation failed");
+ }else if(sslConnected){
+ trans_num++;
+ return;
+ }
+ }
+#endif /* WITH_SSL */
+
+#ifdef WITH_VTP
+ if(trans_num == 1 && VT_Check(inbuf))
+ {
+ VT_Process();
+ return;
+ }
+#endif
+
+ if (msg_type == 0)
+ show_msg(inbuf);
+ else if(msg_type == 0x85)
+ 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
+ send_smb(Client,outbuf);
+ }
+ trans_num++;
+}
+
+
+
+/****************************************************************************
+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);
+}
+
+
+/****************************************************************************
+ Helper function for contruct_reply.
+****************************************************************************/
+
+void construct_reply_common(char *inbuf,char *outbuf)
+{
+ bzero(outbuf,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)); /* bit 7 set
+ means a reply */
+ SSVAL(outbuf,smb_flg2,FLAGS2_LONG_PATH_COMPONENTS); /* say we support long filenames */
+ 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];
+ extern int chain_size;
+ 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;
+ }
+
+ /* 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;
+}
+
+/****************************************************************************
+ process commands from the client
+****************************************************************************/
+void smbd_process(void)
+{
+ extern int Client;
+
+ 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,NMB_PORT,SOCK_DGRAM);
+ }
+#endif
+
+
+ max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
+
+ /* re-initialise the timezone */
+ TimeInit();
+
+ while (True)
+ {
+ int deadtime = lp_deadtime()*60;
+ int counter;
+ int last_keepalive=0;
+ int service_load_counter = 0;
+ BOOL got_smb = False;
+
+ if (deadtime <= 0)
+ deadtime = DEFAULT_SMBD_TIMEOUT;
+
+#if USE_READ_PREDICTION
+ if (lp_readprediction())
+ do_read_prediction();
+#endif
+
+ errno = 0;
+
+ for (counter=SMBD_SELECT_LOOP;
+ !receive_message_or_smb(InBuffer,BUFFER_SIZE,
+ SMBD_SELECT_LOOP*1000,&got_smb);
+ counter += SMBD_SELECT_LOOP)
+ {
+ time_t t;
+ BOOL allidle = True;
+ extern int keepalive;
+
+ if (counter > 365 * 3600) /* big number of seconds. */
+ {
+ counter = 0;
+ service_load_counter = 0;
+ }
+
+ if (smb_read_error == READ_EOF)
+ {
+ DEBUG(3,("end of file from client\n"));
+ return;
+ }
+
+ if (smb_read_error == READ_ERROR)
+ {
+ DEBUG(3,("receive_smb error (%s) exiting\n",
+ strerror(errno)));
+ return;
+ }
+
+ t = time(NULL);
+
+ /* become root again if waiting */
+ unbecome_user();
+
+ /* check for smb.conf reload */
+ if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
+ {
+ service_load_counter = counter;
+
+ /* reload services, if files have changed. */
+ reload_services(True);
+ }
+
+ /*
+ * If reload_after_sighup == True then we got a SIGHUP
+ * and are being asked to reload. Fix from <branko.cibej@hermes.si>
+ */
+
+ if (reload_after_sighup)
+ {
+ DEBUG(0,("Reloading services after SIGHUP\n"));
+ reload_services(False);
+ reload_after_sighup = False;
+ /*
+ * Use this as an excuse to print some stats.
+ */
+ print_stat_cache_statistics();
+ }
+
+ /* automatic timeout if all connections are closed */
+ if (conn_num_open()==0 && counter >= IDLE_CLOSED_TIMEOUT)
+ {
+ DEBUG( 2, ( "Closing idle connection\n" ) );
+ return;
+ }
+
+ if (keepalive && (counter-last_keepalive)>keepalive)
+ {
+ struct cli_state *cli = server_client();
+ if (!send_keepalive(Client)) {
+ DEBUG( 2, ( "Keepalive failed - exiting.\n" ) );
+ return;
+ }
+ /* also send a keepalive to the password server if its still
+ connected */
+ if (cli && cli->initialised)
+ send_keepalive(cli->fd);
+ last_keepalive = counter;
+ }
+
+ /* check for connection timeouts */
+ allidle = conn_idle_all(t, deadtime);
+
+ if (allidle && conn_num_open()>0) {
+ DEBUG(2,("Closing idle connection 2.\n"));
+ return;
+ }
+
+ if(global_machine_pasword_needs_changing)
+ {
+ 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(!trust_password_lock( global_myworkgroup, global_myname, True)) {
+ DEBUG(0,("process: unable to open the machine account password file for \
+machine %s in domain %s.\n", global_myname, global_myworkgroup ));
+ continue;
+ }
+
+ if(!get_trust_account_password( 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 ));
+ trust_password_unlock();
+ continue;
+ }
+
+ /*
+ * Make sure someone else hasn't already done this.
+ */
+
+ if(t < lct + lp_machine_password_timeout()) {
+ trust_password_unlock();
+ global_machine_pasword_needs_changing = False;
+ continue;
+ }
+
+ pstrcpy(remote_machine_list, lp_passwordserver());
+
+ change_trust_account_password( global_myworkgroup, remote_machine_list);
+ trust_password_unlock();
+ global_machine_pasword_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);
+ }
+
+ if(got_smb)
+ process_smb(InBuffer, OutBuffer);
+ else
+ process_local_message(InBuffer, BUFFER_SIZE);
+ }
+}
diff --git a/source/smbd/quotas.c b/source/smbd/quotas.c
new file mode 100644
index 00000000000..b7a538e189e
--- /dev/null
+++ b/source/smbd/quotas.c
@@ -0,0 +1,666 @@
+#ifdef QUOTAS
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+#ifdef LINUX
+
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/quota.h>
+
+#include <mntent.h>
+#include <linux/unistd.h>
+
+_syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
+
+/****************************************************************************
+try to get the disk space from disk quotas (LINUX version)
+****************************************************************************/
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+ 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();
+ seteuid(0);
+ r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
+ seteuid(euser_id);
+
+ /* 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_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
+ (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
+ (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
+ (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
+ )
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+ else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
+ {
+ return(False);
+ }
+ else {
+ if (D.dqb_bsoftlimit == 0)
+ D.dqb_bsoftlimit = D.dqb_bhardlimit;
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ }
+ 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(char *path, int *bsize, int *dfree, int *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 )
+ *dfree -= *dsize ;
+
+ if ( *dfree < 0 )
+ *dfree = 0 ;
+
+ *bsize = 4096 ; /* Cray blocksize */
+
+ return(True) ;
+
+}
+
+
+#elif defined(SUNOS5) || defined(SUNOS4)
+
+#include <fcntl.h>
+#if defined(SUNOS5)
+#include <sys/fs/ufs_quota.h>
+#include <sys/mnttab.h>
+#else /* defined(SUNOS4) */
+#include <ufs/quota.h>
+#include <mntent.h>
+#endif
+
+/****************************************************************************
+try to get the disk space from disk quotas (solaris 2 version)
+****************************************************************************/
+/* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int ret;
+ struct dqblk D;
+#if defined(SUNOS5)
+ struct quotctl command;
+ int file;
+ struct mnttab mnt;
+ static pstring name;
+#else
+ struct mntent *mnt;
+ static pstring name;
+#endif
+ FILE *fd;
+ SMB_STRUCT_STAT sbuf;
+ SMB_DEV_T devno ;
+ static SMB_DEV_T devno_cached = 0 ;
+ int found ;
+
+ if ( sys_stat(path,&sbuf) == -1 )
+ return(False) ;
+
+ devno = sbuf.st_dev ;
+ DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%o\n", path,devno));
+ if ( devno != devno_cached ) {
+ devno_cached = devno ;
+#if defined(SUNOS5)
+ if ((fd = fopen(MNTTAB, "r")) == NULL)
+ return(False) ;
+
+ found = False ;
+ while (getmntent(fd, &mnt) == 0) {
+ if ( sys_stat(mnt.mnt_mountp,&sbuf) == -1 )
+ continue ;
+ DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n",
+ mnt.mnt_mountp,sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+
+ pstrcpy(name,mnt.mnt_mountp) ;
+ pstrcat(name,"/quotas") ;
+ fclose(fd) ;
+#else
+ 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=%o\n",
+ mnt->mnt_dir,sbuf.st_dev));
+ if (sbuf.st_dev == devno) {
+ found = True ;
+ break ;
+ }
+ }
+
+ pstrcpy(name,mnt->mnt_fsname) ;
+ endmntent(fd) ;
+#endif
+
+ if ( ! found )
+ return(False) ;
+ }
+
+ euser_id = geteuid();
+ user_id = getuid();
+
+ setuid(0); /* Solaris seems to want to give info only to super-user */
+ seteuid(0);
+
+#if defined(SUNOS5)
+ DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
+ if((file=open(name, O_RDONLY))<0) {
+ setuid(user_id); /* Restore the original UID status */
+ seteuid(euser_id);
+ 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
+
+ setuid(user_id); /* Restore the original uid status. */
+ seteuid(euser_id);
+
+ if (ret < 0) {
+ DEBUG(2,("disk_quotas ioctl (Solaris) failed\n"));
+ return(False);
+ }
+
+
+ /* 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 = 512;
+ *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
+ *dsize = D.dqb_bsoftlimit;
+ if(*dfree < 0)
+ {
+ *dfree = 0;
+ *dsize = D.dqb_curblocks;
+ }
+
+DEBUG(5,("disk_quotas for path \"%s\" returning bsize %d, dfree %d, dsize %d\n",
+ path,*bsize,*dfree,*dsize));
+
+ return(True);
+}
+
+
+#elif defined(OSF1)
+#include <ufs/quota.h>
+
+/****************************************************************************
+try to get the disk space from disk quotas - OFS1 version
+****************************************************************************/
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t user_id, euser_id;
+ int r, save_errno;
+ struct dqblk D;
+ SMB_STRUCT_STAT S;
+
+ euser_id = geteuid();
+ user_id = getuid();
+
+ setreuid(euser_id, -1);
+ r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
+ if (r)
+ save_errno = errno;
+
+ if (setreuid(user_id, -1) == -1)
+ DEBUG(5,("Unable to reset uid to %d\n", user_id));
+
+ *bsize = DEV_BSIZE;
+
+ if (r)
+ {
+ if (save_errno == EDQUOT) // disk quota exceeded
+ {
+ *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_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 (SGI6)
+/****************************************************************************
+try to get the disk space from disk quotas (IRIX 6.2 version)
+****************************************************************************/
+
+#include <sys/quota.h>
+#include <mntent.h>
+
+BOOL disk_quotas(char *path, int *bsize, int *dfree, int *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();
+ seteuid(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);
+
+ seteuid(euser_id); /* Restore the original uid status. */
+
+ 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);
+
+ seteuid(euser_id); /* Restore the original uid status. */
+
+ 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)
+ )
+ {
+ /*
+ * Fixme!: these are __uint64_t, this may truncate values
+ */
+ *dfree = 0;
+ *dsize = (int) F.d_bcount;
+ }
+ else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
+ {
+ return(False);
+ }
+ else
+ {
+ *dfree = (int)(F.d_blk_softlimit - F.d_bcount);
+ *dsize = (int)F.d_blk_softlimit;
+ }
+
+ }
+ else
+ {
+ seteuid(euser_id); /* Restore the original uid status. */
+ 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(char *path, int *bsize, int *dfree, int *dsize)
+{
+ uid_t euser_id;
+ int r;
+ struct dqblk D;
+#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
+ {
+ uid_t user_id;
+
+ /* for HPUX, real uid must be same as euid to execute quotactl for euid */
+ user_id = getuid();
+ setresuid(euser_id,-1,-1);
+ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
+ if (setresuid(user_id,-1,-1))
+ DEBUG(5,("Unable to reset uid to %d\n", user_id));
+ }
+#else
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ {
+ /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
+ uid_t user_id;
+ gid_t egrp_id;
+
+ /* Need to be root to get quotas in FreeBSD */
+ user_id = getuid();
+ egrp_id = getegid();
+ setuid(0);
+ seteuid(0);
+ 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);
+ setuid(user_id);
+ seteuid(euser_id);
+ }
+#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 /* HAVE_SETRES */
+
+ /* 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 (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
+
+#else
+/* this keeps fussy compilers happy */
+ void quotas_dummy(void) {}
+#endif /* QUOTAS */
+
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index b7b51775bb8..12a39589d62 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Main SMB reply 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
@@ -25,25 +25,39 @@
#include "includes.h"
-#include "loadparm.h"
#include "trans2.h"
+#include "nterr.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 BOOL case_preserve;
+extern BOOL short_case_preserve;
extern pstring sesssetup_user;
+extern fstring global_myworkgroup;
extern int Client;
+extern int global_oplock_break;
+uint32 global_client_caps = 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))
+
+/****************************************************************************
+report a possible attack via the password buffer overflow bug
+****************************************************************************/
+static void overflow_attack(int len)
+{
+ if( DEBUGLVL( 0 ) )
+ {
+ dbgtext( "ERROR: Invalid password length %d.\n", len );
+ dbgtext( "Your machine may be under attack by someone " );
+ dbgtext( "attempting to exploit an old bug.\n" );
+ dbgtext( "Attack was from IP = %s.\n", client_addr(Client) );
+ }
+ exit_server("possible attack");
+}
/****************************************************************************
@@ -51,196 +65,285 @@ a packet to ensure chaining works correctly */
****************************************************************************/
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 remote_machine;
+ extern fstring local_machine;
+ int len;
+ char name_type = 0;
+
+ *name1 = *name2 = 0;
+
+ bzero(outbuf,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);
+
+ 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);
+
+ if (name_type == 'R') {
+ /* We are being asked for a pathworks session ---
+ no thanks! */
+ CVAL(outbuf, 0) = 0x83;
+ break;
+ }
- smb_setlen(outbuf,0);
+ 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();
+
+ if (lp_status(-1)) {
+ claim_connection(NULL,"STATUS.",MAXSTATUS,True);
+ }
+
+ break;
+
+ case 0x89: /* session keepalive request
+ (some old clients produce this?) */
+ CVAL(outbuf,0) = 0x85;
+ 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 0x85: /* 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));
+
+ DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
+ msg_type, msg_flags));
+
+ return(outsize);
+}
- 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;
+/*******************************************************************
+work out what error to give to a failed connection
+********************************************************************/
+static int connection_error(char *inbuf,char *outbuf,int ecode)
+{
+ if (ecode == ERRnoipc) {
+ return(ERROR(ERRDOS,ERRnoipc));
+ }
- add_session_user(remote_machine);
+ return(ERROR(ERRSRV,ecode));
+}
- reload_services(True);
- reopen_logs();
- break;
- case 0x85: /* session keepalive */
- default:
- return(0);
- }
+
+/****************************************************************************
+ parse a share descriptor string
+****************************************************************************/
+static void parse_connect(char *p,char *service,char *user,
+ char *password,int *pwlen,char *dev)
+{
+ char *p2;
+
+ DEBUG(4,("parsing connect string %s\n",p));
+
+ p2 = strrchr(p,'\\');
+ if (p2 == NULL)
+ fstrcpy(service,p);
+ else
+ fstrcpy(service,p2+1);
- DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",timestring(),msg_type,msg_flags));
+ p += strlen(p) + 2;
- return(outsize);
-}
+ fstrcpy(password,p);
+ *pwlen = strlen(password);
+ p += strlen(p) + 2;
-/*******************************************************************
-work out what error to give to a failed connection
-********************************************************************/
-static int connection_error(char *inbuf,char *outbuf,int connection_num)
-{
- switch (connection_num)
+ fstrcpy(dev,p);
+
+ *user = 0;
+ p = strchr(service,'%');
+ if (p != NULL)
{
- 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));
+ *p = 0;
+ fstrcpy(user,p+1);
+ }
}
+
+
/****************************************************************************
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 user;
+ pstring password;
+ pstring dev;
+ int outsize = 0;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int pwlen=0;
+ int ecode = -1;
+
+ *service = *user = *password = *dev = 0;
+
+ parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
- *service = *user = *password = *dev = 0;
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam( user, True);
- vuid = valid_uid(uid);
+ conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
- parse_connect(inbuf,service,user,password,&pwlen,dev);
-
- connection_num = make_connection(service,user,password,pwlen,dev,vuid);
-
- if (connection_num < 0)
- return(connection_error(inbuf,outbuf,connection_num));
+ if (!conn) {
+ return(connection_error(inbuf,outbuf,ecode));
+ }
- 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 user=%s cnum=%d\n",
+ service, user, conn->cnum));
- return(outsize);
+ return(outsize);
}
/****************************************************************************
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);
+ pstring service;
+ pstring user;
+ pstring password;
+ pstring devicename;
+ int ecode = -1;
+ uint16 vuid = SVAL(inbuf,smb_uid);
+ int passlen = SVAL(inbuf,smb_vwv3);
+ char *path;
+ char *p;
+
+ *service = *user = *password = *devicename = 0;
- *service = *user = *password = *devicename = 0;
+ /* we might have to close an old one */
+ if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
+ close_cnum(conn,vuid);
+ }
- /* 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);
+ if (passlen > MAX_PASS_LEN) {
+ overflow_attack(passlen);
+ }
- {
- 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));
- }
+ memcpy(password,smb_buf(inbuf),passlen);
+ password[passlen]=0;
+ path = smb_buf(inbuf) + passlen;
- connection_num = make_connection(service,user,password,passlen,devicename,vuid);
-
- if (connection_num < 0)
- return(connection_error(inbuf,outbuf,connection_num));
+ if (passlen != 24) {
+ if (strequal(password," "))
+ *password = 0;
+ passlen = strlen(password);
+ }
+
+ fstrcpy(service,path+2);
+ p = strchr(service,'\\');
+ if (!p)
+ return(ERROR(ERRSRV,ERRinvnetname));
+ *p = 0;
+ fstrcpy(service,p+1);
+ p = strchr(service,'%');
+ if (p) {
+ *p++ = 0;
+ fstrcpy(user,p);
+ }
+ StrnCpy(devicename,path + strlen(path) + 1,6);
+ DEBUG(4,("Got device type %s\n",devicename));
- outsize = set_message(outbuf,2,strlen(devicename)+1,True);
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam(user, True);
+
+ conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
+
+ if (!conn)
+ return(connection_error(inbuf,outbuf,ecode));
+
+ if (Protocol < PROTOCOL_NT1) {
+ set_message(outbuf,2,strlen(devicename)+1,True);
+ pstrcpy(smb_buf(outbuf),devicename);
+ } else {
+ char *fsname = lp_fstype(SNUM(conn));
+
+ set_message(outbuf,3,3,True);
+
+ p = smb_buf(outbuf);
+ pstrcpy(p,devicename); p = skip_string(p,1); /* device name */
+ pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
+
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+
+ /* 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);
+ }
- DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
+ DEBUG(3,("tconX service=%s user=%s\n",
+ service, user));
- /* set the incoming and outgoing tid to the just created one */
- SSVAL(inbuf,smb_tid,connection_num);
- SSVAL(outbuf,smb_tid,connection_num);
-
- CVAL(outbuf,smb_vwv0) = smb_com2;
- SSVAL(outbuf,smb_vwv1,(chain_size + outsize)-4);
-
- strcpy(smb_buf(outbuf),devicename);
-
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ /* 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);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
@@ -249,135 +352,311 @@ 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(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));
+ DEBUG(3,("ignoring ioctl\n"));
+#if 0
+ /* we just say it succeeds and hope its all OK.
+ some day it would be nice to interpret them individually */
+ return set_message(outbuf,1,0,True);
+#else
+ return(ERROR(ERRSRV,ERRnosupport));
+#endif
+}
+
+/****************************************************************************
+ always return an error: it's just a matter of which one...
+ ****************************************************************************/
+static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
+ char *smb_passwd, int smb_passlen,
+ char *smb_nt_passwd, int smb_nt_passlen)
+{
+ struct smb_passwd *smb_trust_acct = NULL; /* check if trust account exists */
+ if (lp_security() == SEC_USER)
+ {
+ smb_trust_acct = getsmbpwnam(user);
+ }
+ else
+ {
+ DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+ }
+
+ if (smb_trust_acct == NULL)
+ {
+ /* lkclXXXX: workstation entry doesn't exist */
+ DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_NO_SUCH_USER));
+ }
+ else
+ {
+ if ((smb_passlen != 24) || (smb_nt_passlen != 24))
+ {
+ DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+ }
+
+ if (!smb_password_ok(smb_trust_acct, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd))
+ {
+ DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+ }
+
+ if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_DOMTRUST))
+ {
+ DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT));
+ }
+
+ if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_SVRTRUST))
+ {
+ DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT));
+ }
+
+ if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_WSTRUST))
+ {
+ DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT));
+ }
+ }
+
+ /* don't know what to do: indicate logon failure */
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
}
/****************************************************************************
reply to a session setup command
****************************************************************************/
-int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int outsize = 0;
- int sess_uid;
+ uint16 sess_vuid;
int gid;
- int smb_com2;
- int smb_off2;
+ int uid;
int smb_bufsize;
- int smb_mpxmax;
- int smb_vc_num;
- uint32 smb_sesskey;
- int smb_apasslen;
+ int smb_apasslen = 0;
pstring smb_apasswd;
int smb_ntpasslen = 0;
pstring smb_ntpasswd;
BOOL valid_nt_password = False;
pstring user;
+ pstring orig_user;
BOOL guest=False;
+ static BOOL done_sesssetup = False;
+ BOOL doencrypt = SMBENCRYPT();
+ char *domain = "";
*smb_apasswd = 0;
+ *smb_ntpasswd = 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);
+ if (smb_apasslen > MAX_PASS_LEN)
+ {
+ overflow_attack(smb_apasslen);
+ }
+
memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
- StrnCpy(user,smb_buf(inbuf)+smb_apasslen,sizeof(user)-1);
+ smb_apasswd[smb_apasslen] = 0;
+ pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
+
+ if (!doencrypt && (lp_security() != SEC_SERVER)) {
+ smb_apasslen = strlen(smb_apasswd);
+ }
} 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) {
+ enum remote_arch_types ra_type = get_remote_arch();
+ char *p = smb_buf(inbuf);
+
+ 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_WIN95)
+ {
+ if(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))
+ set_remote_arch( RA_WINNT);
+ else
+ set_remote_arch( RA_WIN95);
+ }
+
+ if (passlen1 != 24 && passlen2 != 24)
+ doencrypt = False;
+
+ if (passlen1 > MAX_PASS_LEN) {
+ overflow_attack(passlen1);
+ }
+
+ 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;
+ }
+
+ if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
/* Save the lanman2 password and the NT md4 password. */
smb_apasslen = passlen1;
memcpy(smb_apasswd,p,smb_apasslen);
+ smb_apasswd[smb_apasslen] = 0;
smb_ntpasslen = passlen2;
memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
+ smb_ntpasswd[smb_ntpasslen] = 0;
} 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);
+ /* we use the first password that they gave */
+ smb_apasslen = passlen1;
+ StrnCpy(smb_apasswd,p,smb_apasslen);
+
+ /* trim the password */
+ smb_apasslen = strlen(smb_apasswd);
+
+ /* wfwg sometimes uses a space instead of a null */
+ if (strequal(smb_apasswd," ")) {
+ smb_apasslen = 0;
+ *smb_apasswd = 0;
}
}
- 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);
+ fstrcpy(user,p); p = skip_string(p,1);
+ domain = p;
+
DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n",
- p,skip_string(p,1),skip_string(p,2)));
+ domain,skip_string(p,1),skip_string(p,2)));
}
DEBUG(3,("sesssetupX:name=[%s]\n",user));
+ /* If name ends in $ then I think it's asking about whether a */
+ /* computer with that name (minus the $) has access. For now */
+ /* say yes to everything ending in $. */
+ if ((user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24))
+ {
+ return session_trust_account(conn, inbuf, outbuf, user,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen);
+ }
+
+ /* If no username is sent use the guest account */
if (!*user)
- strcpy(user,lp_guestaccount(-1));
+ {
+ pstrcpy(user,lp_guestaccount(-1));
+ /* If no user and no password then set guest flag. */
+ if( *smb_apasswd == 0)
+ guest = True;
+ }
strlower(user);
- strcpy(sesssetup_user,user);
+ /*
+ * In share level security, only overwrite sesssetup_use if
+ * it's a non null-session share. Helps keep %U and %G
+ * working.
+ */
+
+ if((lp_security() != SEC_SHARE) || *user)
+ pstrcpy(sesssetup_user,user);
reload_services(True);
+ /*
+ * Save the username before mapping. We will use
+ * the original username sent to us for security=server
+ * and security=domain checking.
+ */
+
+ pstrcpy( orig_user, user);
+
+ /*
+ * Pass the user through the NT -> unix user mapping
+ * function.
+ */
+
+ (void)map_username(user);
+
+ /*
+ * Do any UNIX username case mangling.
+ */
+ (void)Get_Pwnam( user, True);
+
add_session_user(user);
+ /*
+ * Check if the given username was the guest user with no password.
+ */
- if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
- !check_hosts_equiv(user))
+ if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
+ guest = True;
+
+ if (!guest && !(lp_security() == SEC_SERVER &&
+ /* Check with orig_user for security=server and
+ security=domain. */
+ server_validate(orig_user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen)) &&
+ !(lp_security() == SEC_DOMAIN &&
+ domain_client_validate(orig_user, domain,
+ smb_apasswd, smb_apasslen,
+ smb_ntpasswd, smb_ntpasslen)) &&
+ !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)
+ first. This is superior as the passwords are mixed case
+ 128 length unicode */
+ if(smb_ntpasslen)
{
- if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL,True))
+ if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL))
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 (!valid_nt_password && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
{
if (lp_security() >= SEC_USER) {
#if (GUEST_SESSSETUP == 0)
@@ -389,7 +668,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
#endif
}
if (*smb_apasswd || !Get_Pwnam(user,True))
- strcpy(user,lp_guestaccount(-1));
+ pstrcpy(user,lp_guestaccount(-1));
DEBUG(3,("Registered username %s for guest access\n",user));
guest = True;
}
@@ -397,7 +676,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
if (!Get_Pwnam(user,True)) {
DEBUG(3,("No such user %s - using guest account\n",user));
- strcpy(user,lp_guestaccount(-1));
+ pstrcpy(user,lp_guestaccount(-1));
guest = True;
}
@@ -413,15 +692,15 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
/* it's ok - setup a reply */
if (Protocol < PROTOCOL_NT1) {
- outsize = set_message(outbuf,3,0,True);
+ set_message(outbuf,3,0,True);
} else {
char *p;
- outsize = set_message(outbuf,3,3,True);
+ 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);
+ pstrcpy(p,"Unix"); p = skip_string(p,1);
+ pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
+ pstrcpy(p,global_myworkgroup); p = skip_string(p,1);
+ set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
/* perhaps grab OS version here?? */
}
@@ -436,58 +715,84 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
return(ERROR(ERRSRV,ERRbadpw));
}
gid = pw->pw_gid;
- SSVAL(outbuf,smb_uid,(uint16)pw->pw_uid);
- SSVAL(inbuf,smb_uid,(uint16)pw->pw_uid);
+ uid = 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);
+ sess_vuid = register_vuid(uid,gid,user,sesssetup_user,guest);
- maxxmit = MIN(maxxmit,smb_bufsize);
+ SSVAL(outbuf,smb_uid,sess_vuid);
+ SSVAL(inbuf,smb_uid,sess_vuid);
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
+ if (!done_sesssetup)
+ max_send = MIN(max_send,smb_bufsize);
- return(outsize);
+ DEBUG(6,("Client requested max send size of %d\n", max_send));
+
+ done_sesssetup = True;
+
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
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 st;
+
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ unix_convert(name,conn,0,&bad_path,&st);
mode = SVAL(inbuf,smb_vwv0);
- if (check_name(name,cnum))
- ok = directory_exist(name,NULL);
+ if (check_name(name,conn)) {
+ if(VALID_STAT(st))
+ ok = S_ISDIR(st.st_mode);
+ else
+ ok = directory_exist(name,NULL);
+ }
if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
-
+ {
+ /* 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)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+#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
+
+ return(UNIXERROR(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));
+
return(outsize);
}
@@ -495,66 +800,77 @@ 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);
-
- strcpy(fname,smb_buf(inbuf) + 1);
- unix_convert(fname,cnum);
+ BOOL bad_path = False;
+
+ pstrcpy(fname,smb_buf(inbuf) + 1);
/* 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) || dos_stat(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;
+ }
+
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))
+ if (!is_8_3(fname, True))
SSVAL(outbuf,smb_flg2,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 ) );
return(outsize);
}
@@ -563,36 +879,43 @@ 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 st;
+ BOOL bad_path = False;
+
+ pstrcpy(fname,smb_buf(inbuf) + 1);
+ unix_convert(fname,conn,0,&bad_path,&st);
mode = SVAL(inbuf,smb_vwv0);
mtime = make_unix_date3(inbuf+smb_vwv1);
- if (directory_exist(fname,NULL))
+ if (VALID_STAT_OF_DIR(st) || directory_exist(fname,NULL))
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;
+ }
+
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 ) );
return(outsize);
}
@@ -601,13 +924,10 @@ 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;
-
- cnum = SVAL(inbuf,smb_tid);
+ SMB_BIG_UINT dfree,dsize,bsize;
sys_disk_free(".",&bsize,&dfree,&dsize);
@@ -617,9 +937,9 @@ 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));
+
return(outsize);
}
@@ -628,15 +948,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;
@@ -651,6 +971,7 @@ int reply_search(char *inbuf,char *outbuf)
BOOL check_descend = False;
BOOL expect_close = False;
BOOL can_open = True;
+ BOOL bad_path = False;
*mask = *directory = *fname = 0;
@@ -658,8 +979,6 @@ 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);
@@ -676,28 +995,34 @@ int reply_search(char *inbuf,char *outbuf)
{
pstring dir2;
- strcpy(directory,smb_buf(inbuf)+1);
- strcpy(dir2,smb_buf(inbuf)+1);
- unix_convert(directory,cnum);
+ pstrcpy(directory,smb_buf(inbuf)+1);
+ pstrcpy(dir2,smb_buf(inbuf)+1);
+ unix_convert(directory,conn,0,&bad_path,NULL);
unix_format(dir2);
- if (!check_name(directory,cnum))
- can_open = False;
+ if (!check_name(directory,conn))
+ can_open = False;
p = strrchr(dir2,'/');
if (p == NULL)
- {strcpy(mask,dir2);*dir2 = 0;}
+ {
+ pstrcpy(mask,dir2);
+ *dir2 = 0;
+ }
else
- {*p = 0;strcpy(mask,p+1);}
+ {
+ *p = 0;
+ pstrcpy(mask,p+1);
+ }
p = strrchr(directory,'/');
if (!p)
- *directory = 0;
+ *directory = 0;
else
- *p = 0;
+ *p = 0;
if (strlen(directory) == 0)
- strcpy(directory,"./");
+ pstrcpy(directory,"./");
bzero(status,21);
CVAL(status,0) = dirtype;
}
@@ -707,10 +1032,10 @@ int reply_search(char *inbuf,char *outbuf)
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)
+ conn->dirptr = dptr_fetch(status+12,&dptr_num);
+ if (!conn->dirptr)
goto SearchEmpty;
- string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
+ string_set(&conn->dirpath,dptr_path(dptr_num));
if (!case_sensitive)
strnorm(mask);
}
@@ -721,32 +1046,45 @@ int reply_search(char *inbuf,char *outbuf)
if ((p = strrchr(mask,' ')))
{
fstring ext;
- strcpy(ext,p+1);
+ fstrcpy(ext,p+1);
*p = 0;
trim_string(mask,NULL," ");
- strcat(mask,".");
- strcat(mask,ext);
+ pstrcat(mask,".");
+ pstrcat(mask,ext);
}
}
+ /* Convert the formatted mask. (This code lives in trans2.c) */
+ mask_convert(mask);
+
{
- for (p=mask; *p; p++)
+ int skip;
+ p = mask;
+ while(*p)
+ {
+ if((skip = skip_multibyte_char( *p )) != 0 )
{
- if (*p != '?' && *p != '*' && !isdoschar(*p))
- {
- DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
- *p = '?';
- }
+ p += skip;
}
+ else
+ {
+ if (*p != '?' && *p != '*' && !isdoschar(*p))
+ {
+ DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
+ *p = '?';
+ }
+ p++;
+ }
+ }
}
if (!strchr(mask,'.') && strlen(mask)>8)
{
fstring tmp;
- strcpy(tmp,&mask[8]);
+ fstrcpy(tmp,&mask[8]);
mask[8] = '.';
mask[9] = 0;
- strcat(mask,tmp);
+ pstrcat(mask,tmp);
}
DEBUG(5,("mask=%s directory=%s\n",mask,directory));
@@ -759,9 +1097,20 @@ int reply_search(char *inbuf,char *outbuf)
if (status_len == 0)
{
- dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
+ dptr_num = dptr_create(conn,directory,expect_close,SVAL(inbuf,smb_pid));
if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRnofids));
+ {
+ if(dptr_num == -2)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return (UNIXERROR(ERRDOS,ERRnofids));
+ }
+ return(ERROR(ERRDOS,ERRnofids));
+ }
}
DEBUG(4,("dptr_num is %d\n",dptr_num));
@@ -771,7 +1120,7 @@ int reply_search(char *inbuf,char *outbuf)
if ((dirtype&0x1F) == aVOLID)
{
memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(cnum)),0,aVOLID,0);
+ 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;
@@ -781,15 +1130,16 @@ int reply_search(char *inbuf,char *outbuf)
}
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))
+ 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(cnum,mask,dirtype,fname,&size,&mode,&date,check_descend);
+ !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
if (!finished)
{
memcpy(p,status,21);
@@ -842,12 +1192,11 @@ int reply_search(char *inbuf,char *outbuf)
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(),
+ DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
smb_fn_name(CVAL(inbuf,smb_com)),
- mask,directory,cnum,dirtype,numentries,maxentries));
+ mask, directory, dirtype, numentries, maxentries ) );
return(outsize);
}
@@ -856,17 +1205,14 @@ 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;
char status[21];
int dptr_num= -1;
- cnum = SVAL(inbuf,smb_tid);
-
outsize = set_message(outbuf,1,0,True);
path = smb_buf(inbuf) + 1;
status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
@@ -884,7 +1230,7 @@ int reply_fclose(char *inbuf,char *outbuf)
SSVAL(outbuf,smb_vwv0,0);
- DEBUG(3,("%s search close cnum=%d\n",timestring(),cnum));
+ DEBUG(3,("search close\n"));
return(outsize);
}
@@ -893,63 +1239,88 @@ 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);
+
share_mode = SVAL(inbuf,smb_vwv0);
- strcpy(fname,smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ unix_convert(fname,conn,0,&bad_path,NULL);
- fnum = find_free_file();
- if (fnum < 0)
+ fsp = file_new();
+ if (!fsp)
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;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- unixmode = unix_mode(cnum,aARCH);
+ }
+
+ unixmode = unix_mode(conn,aARCH);
- open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
+ open_file_shared(fsp,conn,fname,share_mode,3,unixmode,
+ oplock_request,&rmode,NULL);
- if (!Files[fnum].open)
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fsp,False);
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);
+ close_file(fsp,False);
return(ERROR(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(fsp->granted_oplock)
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
return(outsize);
}
@@ -957,165 +1328,235 @@ 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;
+
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
/* XXXX we need to handle passed times, sattr and flags */
- strcpy(fname,smb_buf(inbuf));
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf));
+ unix_convert(fname,conn,0,&bad_path,NULL);
- /* 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)
+ fsp = file_new();
+ if (!fsp)
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;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- unixmode = unix_mode(cnum,smb_attr | aARCH);
+ unixmode = unix_mode(conn,smb_attr | aARCH);
- open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
- &rmode,&smb_action);
+ open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
- if (!Files[fnum].open)
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fsp,False);
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);
+ close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
- 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);
+ /* 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 && fsp->granted_oplock) {
+ 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 && fsp->granted_oplock) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+
+ 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);
+ 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);
- 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 ) );
+
+ 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);
+
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);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ unix_convert(fname,conn,0,&bad_path,NULL);
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);
- if (com == SMBmknew && file_exist(fname,NULL))
- return(ERROR(ERRDOS,ERRfilexists));
-
- fnum = find_free_file();
- if (fnum < 0)
+ fsp = file_new();
+ if (!fsp)
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;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if(com == SMBmknew)
+ {
+ /* We should fail if file exists. */
+ ofun = 0x10;
+ }
+ else
+ {
+ /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+ ofun = 0x12;
+ }
- open_file(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* Open file in dos compatibility share mode. */
+ open_file_shared(fsp,conn,fname,(DENY_FCB<<4)|0xF, ofun, unixmode,
+ oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
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(fsp->granted_oplock)
+ 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_ptr->fd, createmode, (int)unixmode ) );
+
return(outsize);
}
@@ -1123,45 +1564,73 @@ 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);
+
createmode = SVAL(inbuf,smb_vwv0);
- sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
- unix_convert(fname,cnum);
+ pstrcpy(fname,smb_buf(inbuf)+1);
+ pstrcat(fname,"/TMXXXXXX");
+ unix_convert(fname,conn,0,&bad_path,NULL);
- unixmode = unix_mode(cnum,createmode);
+ unixmode = unix_mode(conn,createmode);
- fnum = find_free_file();
- if (fnum < 0)
+ fsp = file_new();
+ if (fsp)
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;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- strcpy(fname2,(char *)mktemp(fname));
+ pstrcpy(fname2,(char *)mktemp(fname));
- open_file(fnum,cnum,fname2,O_RDWR | O_CREAT | O_TRUNC,unixmode);
+ /* Open file in dos compatibility share mode. */
+ /* We should fail if file exists. */
+ open_file_shared(fsp,conn,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode,
+ oplock_request, NULL, NULL);
- if (!Files[fnum].open)
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
outsize = set_message(outbuf,1,2 + strlen(fname2),True);
- SSVAL(outbuf,smb_vwv0,fnum);
+ SSVAL(outbuf,smb_vwv0,fsp->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));
+ pstrcpy(smb_buf(outbuf) + 1,fname2);
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+ }
+ if(fsp->granted_oplock)
+ CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
+ DEBUG( 2, ( "created temp file %s\n", fname2 ) );
+ DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
+ fname2, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
+
return(outsize);
}
@@ -1169,31 +1638,32 @@ int reply_ctemp(char *inbuf,char *outbuf)
/*******************************************************************
check if a user is allowed to delete a file
********************************************************************/
-static BOOL can_delete(char *fname,int cnum,int dirtype)
+static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
{
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
int fmode;
- if (!CAN_WRITE(cnum)) return(False);
+ if (!CAN_WRITE(conn)) return(False);
- if (sys_lstat(fname,&sbuf) != 0) return(False);
- fmode = dos_mode(cnum,fname,&sbuf);
+ if (dos_lstat(fname,&sbuf) != 0) return(False);
+ fmode = dos_mode(conn,fname,&sbuf);
if (fmode & aDIR) return(False);
- if (fmode & aRONLY) return(False);
+ if (!lp_delete_readonly(SNUM(conn))) {
+ if (fmode & aRONLY) return(False);
+ }
if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
return(False);
- if (!check_file_sharing(cnum,fname)) return(False);
+ if (!check_file_sharing(conn,fname,False)) return(False);
return(True);
}
/****************************************************************************
reply to a unlink
****************************************************************************/
-int reply_unlink(char *inbuf,char *outbuf)
+int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
pstring name;
- int cnum;
int dirtype;
pstring directory;
pstring mask;
@@ -1202,63 +1672,68 @@ int reply_unlink(char *inbuf,char *outbuf)
int error = ERRnoaccess;
BOOL has_wild;
BOOL exists=False;
+ BOOL bad_path = False;
*directory = *mask = 0;
- cnum = SVAL(inbuf,smb_tid);
dirtype = SVAL(inbuf,smb_vwv0);
- strcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(name,smb_buf(inbuf) + 1);
DEBUG(3,("reply_unlink : %s\n",name));
- unix_convert(name,cnum);
+ unix_convert(name,conn,0,&bad_path,NULL);
p = strrchr(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);
+ check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
if (!has_wild) {
- strcat(directory,"/");
- strcat(directory,mask);
- if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++;
+ pstrcat(directory,"/");
+ pstrcat(directory,mask);
+ if (can_delete(directory,conn,dirtype) && !dos_unlink(directory)) count++;
if (!count) exists = file_exist(directory,NULL);
} else {
void *dirptr = NULL;
char *dname;
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ 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 = ERRbadfile;
if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ pstrcpy(mask,"*");
while ((dname = ReadDirName(dirptr)))
{
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
if(!mask_match(fname, mask, case_sensitive, False)) continue;
error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- if (!can_delete(fname,cnum,dirtype)) continue;
- if (!sys_unlink(fname)) count++;
+ slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+ if (!can_delete(fname,conn,dirtype)) continue;
+ if (!dos_unlink(fname)) count++;
DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
}
CloseDir(dirptr);
@@ -1269,7 +1744,14 @@ int reply_unlink(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,0,0,True);
@@ -1281,91 +1763,113 @@ int reply_unlink(char *inbuf,char *outbuf)
/****************************************************************************
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;
+ size_t maxcount,mincount;
+ size_t nread = 0;
+ SMB_OFF_T startpos;
char *header = outbuf;
- int ret=0;
- int fd;
- char *fname;
+ ssize_t ret=0;
+ files_struct *fsp;
+
+ /*
+ * 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);
+ transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+ DEBUG(5,("readbraw - oplock break finished\n"));
+ return -1;
+ }
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ fsp = file_fsp(inbuf,smb_vwv0);
startpos = IVAL(inbuf,smb_vwv1);
- maxcount = SVAL(inbuf,smb_vwv3);
- mincount = SVAL(inbuf,smb_vwv4);
+#ifdef LARGE_SMB_OFF_T
+ if(CVAL(inbuf,smb_wct) == 10) {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
+ if(startpos < 0) {
+ DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
+ (double)startpos ));
+ _smb_setlen(header,0);
+ transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+ return(-1);
+ }
+ }
+#endif /* LARGE_SMB_OFF_T */
+ 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 (!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;
- }
-
+ if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+ DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fsp->fnum));
+ _smb_setlen(header,0);
+ transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+ return(-1);
+ }
- if (!is_locked(fnum,cnum,maxcount,startpos))
- {
- int size = Files[fnum].size;
- int sizeneeded = startpos + maxcount;
+ if (!is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
+ {
+ SMB_OFF_T size = fsp->size;
+ SMB_OFF_T 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;
- }
-
- nread = MIN(maxcount,size - startpos);
+ if (size < sizeneeded)
+ {
+ SMB_STRUCT_STAT st;
+ if (sys_fstat(fsp->fd_ptr->fd,&st) == 0)
+ size = st.st_size;
+ if (!fsp->can_write)
+ fsp->size = size;
}
+ nread = MIN(maxcount,(size - startpos));
+ }
+
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));
+ DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
+ fsp->fnum, (double)startpos,
+ maxcount, mincount, nread ) );
#if UNSAFE_READRAW
{
int predict=0;
_smb_setlen(header,nread);
- if (!Files[fnum].can_write)
- predict = read_predict(fd,startpos,header+4,NULL,nread);
+#if USE_READ_PREDICTION
+ if (!fsp->can_write)
+ predict = read_predict(fsp->fd_ptr->fd,startpos,header+4,NULL,nread);
+#endif /* USE_READ_PREDICTION */
if ((nread-predict) > 0)
- seek_file(fnum,startpos + predict);
+ seek_file(fsp,startpos + predict);
- ret = transfer_file(fd,Client,nread-predict,header,4+predict,
+ ret = (ssize_t)transfer_file(fsp->fd_ptr->fd,Client,(SMB_OFF_T)(nread-predict),header,4+predict,
startpos+predict);
}
if (ret != nread+4)
DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
- fname,startpos,nread,ret));
+ fsp->fsp_name,startpos,nread,ret));
-#else
- ret = read_file(fnum,header+4,startpos,nread,nread,-1,False);
+#else /* UNSAFE_READRAW */
+ ret = read_file(fsp,header+4,startpos,nread);
if (ret < mincount) ret = 0;
_smb_setlen(header,ret);
transfer_file(0,Client,0,header,4+ret,0);
-#endif
+#endif /* UNSAFE_READRAW */
DEBUG(5,("readbraw finished\n"));
return -1;
@@ -1375,22 +1879,20 @@ int reply_readbraw(char *inbuf, char *outbuf)
/****************************************************************************
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;
+ ssize_t nread = -1;
char *data;
int outsize = 0;
- uint32 startpos, numtoread;
+ SMB_OFF_T startpos;
+ size_t numtoread;
int eclass;
uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
numtoread = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
@@ -1399,21 +1901,32 @@ int reply_lockread(char *inbuf,char *outbuf)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
+ if(!do_lock( fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode)) {
+ if((ecode == ERRlock) && 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))
+ return -1;
+ }
return (ERROR(eclass,ecode));
+ }
+
+ nread = read_file(fsp,data,startpos,numtoread);
- 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));
-
+
+ DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
+ fsp->fnum, numtoread, nread ) );
+
return(outsize);
}
@@ -1421,20 +1934,18 @@ int reply_lockread(char *inbuf,char *outbuf)
/****************************************************************************
reply to a read
****************************************************************************/
-int reply_read(char *inbuf,char *outbuf)
+int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_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);
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
numtoread = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
@@ -1443,11 +1954,11 @@ int reply_read(char *inbuf,char *outbuf)
numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
data = smb_buf(outbuf) + 3;
- if (is_locked(fnum,cnum,numtoread,startpos))
+ if (is_locked(fsp,conn,numtoread,startpos, F_RDLCK))
return(ERROR(ERRDOS,ERRlock));
if (numtoread > 0)
- nread = read_file(fnum,data,startpos,numtoread,numtoread,-1,False);
+ nread = read_file(fsp,data,startpos,numtoread);
if (nread < 0)
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -1458,8 +1969,9 @@ 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, numtoread, nread ) );
+
return(outsize);
}
@@ -1467,82 +1979,70 @@ 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;
- cnum = SVAL(inbuf,smb_tid);
+ /* If it's an IPC, pass off the pipe handler. */
+ if (IS_IPC(conn))
+ 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);
+ CHECK_ERROR(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))
+#ifdef LARGE_SMB_OFF_T
+ if(CVAL(inbuf,smb_wct) == 12) {
+ /*
+ * This is a large offset (64 bit) read.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ if (is_locked(fsp,conn,smb_maxcnt,startpos, F_RDLCK))
return(ERROR(ERRDOS,ERRlock));
- nread = read_file(fnum,data,smb_offs,smb_maxcnt,smb_maxcnt,-1,False);
- ok = True;
+ nread = read_file(fsp,data,startpos,smb_maxcnt);
if (nread < 0)
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));
+ DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
+ fsp->fnum, smb_mincnt, smb_maxcnt, nread ) );
- 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);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
-
/****************************************************************************
reply to a writebraw (core+ or LANMAN1.0 protocol)
****************************************************************************/
-int reply_writebraw(char *inbuf,char *outbuf)
+int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int nwritten=0;
- int total_written=0;
- int numtowrite=0;
- int cnum,fnum;
- int outsize = 0;
- long startpos;
+ 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;
- int tcount;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
tcount = IVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv3);
@@ -1562,17 +2062,17 @@ int reply_writebraw(char *inbuf,char *outbuf)
CVAL(inbuf,smb_com) = SMBwritec;
CVAL(outbuf,smb_com) = SMBwritec;
- if (is_locked(fnum,cnum,tcount,startpos))
+ if (is_locked(fsp,conn,tcount,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if (seek_file(fnum,startpos) != startpos)
- DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
+ if (seek_file(fsp,startpos) != startpos)
+ DEBUG(0,("couldn't seek to %.0f in writebraw\n",(double)startpos));
if (numtowrite>0)
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,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, numtowrite, nwritten, write_through));
if (nwritten < numtowrite)
return(UNIXERROR(ERRHRD,ERRdiskfull));
@@ -1587,7 +2087,7 @@ int reply_writebraw(char *inbuf,char *outbuf)
send_smb(Client,outbuf);
/* Now read the raw data into the buffer and write it */
- if(read_smb_length(Client,inbuf,0) == -1) {
+ if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
exit_server("secondary writebraw failed");
}
@@ -1600,7 +2100,7 @@ int reply_writebraw(char *inbuf,char *outbuf)
tcount,nwritten,numtowrite));
}
- nwritten = transfer_file(Client,Files[fnum].fd,numtowrite,NULL,0,
+ nwritten = transfer_file(Client,fsp->fd_ptr->fd,(SMB_OFF_T)numtowrite,NULL,0,
startpos+nwritten);
total_written += nwritten;
@@ -1609,16 +2109,16 @@ int reply_writebraw(char *inbuf,char *outbuf)
CVAL(outbuf,smb_com) = SMBwritec;
SSVAL(outbuf,smb_vwv0,total_written);
- if (nwritten < numtowrite) {
+ if (nwritten < (ssize_t)numtowrite) {
CVAL(outbuf,smb_rcls) = ERRHRD;
SSVAL(outbuf,smb_err,ERRdiskfull);
}
- if (lp_syncalways(SNUM(cnum)) || write_through)
- sync_file(fnum);
+ if (lp_syncalways(SNUM(conn)) || write_through)
+ sync_file(conn,fsp);
- DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
- timestring(),fnum,cnum,startpos,numtowrite,total_written));
+ DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
+ fsp->fnum, (double)startpos, numtowrite, total_written));
/* we won't return a status if write through is not selected - this
follows what WfWg does */
@@ -1628,35 +2128,32 @@ int reply_writebraw(char *inbuf,char *outbuf)
return(outsize);
}
-
/****************************************************************************
reply to a writeunlock (core+)
****************************************************************************/
-int reply_writeunlock(char *inbuf,char *outbuf)
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,fnum;
- int nwritten = -1;
- int outsize = 0;
+ ssize_t nwritten = -1;
+ size_t numtowrite;
+ SMB_OFF_T startpos;
char *data;
- uint32 numtowrite,startpos;
int eclass;
uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
numtowrite = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fnum,cnum,numtowrite,startpos))
+ if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
+ seek_file(fsp,startpos);
/* The special X/Open SMB protocol handling of
zero length writes is *NOT* done for
@@ -1664,68 +2161,62 @@ int reply_writeunlock(char *inbuf,char *outbuf)
if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,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))
+ if(!do_unlock(fsp, conn, numtowrite, startpos, &eclass, &ecode))
return(ERROR(eclass,ecode));
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));
-
+ DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten ) );
+
return(outsize);
}
-
/****************************************************************************
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 dum_size,int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int startpos;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ SMB_OFF_T startpos;
char *data;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ int outsize = 0;
- dum1 = dum2 = 0;
-
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
numtowrite = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
data = smb_buf(inbuf) + 3;
- if (is_locked(fnum,cnum,numtowrite,startpos))
+ if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
+ seek_file(fsp,startpos);
/* 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);
+ nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos);
else
- nwritten = write_file(fnum,data,numtowrite);
+ nwritten = write_file(fsp,data,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));
@@ -1734,13 +2225,14 @@ int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
SSVAL(outbuf,smb_vwv0,nwritten);
- if (nwritten < numtowrite) {
+ if (nwritten < (ssize_t)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));
-
+ DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten));
+
return(outsize);
}
@@ -1748,142 +2240,125 @@ int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
/****************************************************************************
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;
+ int smb_doff = SVAL(inbuf,smb_vwv11);
char *data;
- cnum = SVAL(inbuf,smb_tid);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
data = smb_base(inbuf) + smb_doff;
- if (is_locked(fnum,cnum,smb_dsize,smb_offs))
+#ifdef LARGE_SMB_OFF_T
+ if(CVAL(inbuf,smb_wct) == 14) {
+ /*
+ * This is a large offset (64 bit) write.
+ */
+ startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,smb_offs);
+ seek_file(fsp,startpos);
/* 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,numtowrite);
- if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
+ if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
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 (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, numtowrite, 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);
+ 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 dum_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);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
mode = SVAL(inbuf,smb_vwv1) & 3;
startpos = IVAL(inbuf,smb_vwv2);
switch (mode & 3)
- {
+ {
case 0: umode = SEEK_SET; break;
case 1: umode = SEEK_CUR; break;
case 2: umode = SEEK_END; break;
default:
umode = SEEK_SET; break;
- }
-
- res = lseek(Files[fnum].fd,startpos,umode);
- Files[fnum].pos = res;
+ }
+
+ res = sys_lseek(fsp->fd_ptr->fd,startpos,umode);
+ 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));
-
+ DEBUG(3,("lseek fnum=%d ofs=%.0f mode=%d\n",
+ fsp->fnum, (double)startpos, mode));
+
return(outsize);
}
-
/****************************************************************************
reply to a flush
****************************************************************************/
-int reply_flush(char *inbuf,char *outbuf)
+int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum, fnum;
int outsize = set_message(outbuf,0,0,True);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- if (fnum != 0xFFFF) {
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ if (fsp) {
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
}
- if (fnum == 0xFFFF)
- {
- int i;
- for (i=0;i<MAX_OPEN_FILES;i++)
- if (OPEN_FNUM(i))
- sync_file(i);
- }
- else
- sync_file(fnum);
+ if (!fsp) {
+ file_sync_all(conn);
+ } else {
+ sync_file(conn,fsp);
+ }
- DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
+ DEBUG(3,("flush\n"));
return(outsize);
}
@@ -1891,158 +2366,187 @@ int reply_flush(char *inbuf,char *outbuf)
/****************************************************************************
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 = set_message(outbuf,0,0,True);
+ DEBUG(3,("exit\n"));
+
+ 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 dum_size, int dum_buffsize)
{
- int fnum,cnum;
- int outsize = 0;
- time_t mtime;
- int32 eclass = 0, err = 0;
-
- outsize = set_message(outbuf,0,0,True);
+ int outsize = 0;
+ time_t mtime;
+ int32 eclass = 0, err = 0;
+ files_struct *fsp = NULL;
- cnum = SVAL(inbuf,smb_tid);
+ outsize = set_message(outbuf,0,0,True);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
-
- if(HAS_CACHED_ERROR(fnum)) {
- eclass = Files[fnum].wbmpx_ptr->wr_errclass;
- err = Files[fnum].wbmpx_ptr->wr_error;
- }
+ /* If it's an IPC, pass off to the pipe handler. */
+ if (IS_IPC(conn)) {
+ return reply_pipe_close(conn, inbuf,outbuf);
+ }
- mtime = make_unix_date3(inbuf+smb_vwv1);
+ fsp = file_fsp(inbuf,smb_vwv0);
- close_file(fnum);
+ /*
+ * We can only use CHECK_FSP if we know it's not a directory.
+ */
- /* try and set the date */
- set_filetime(Files[fnum].name,mtime);
+ if(!fsp || !fsp->open || (fsp->conn != conn))
+ return(ERROR(ERRDOS,ERRbadfid));
- /* We have a cached error */
- if(eclass || err)
- return(ERROR(eclass,err));
+ if(HAS_CACHED_ERROR(fsp)) {
+ eclass = fsp->wbmpx_ptr->wr_errclass;
+ err = fsp->wbmpx_ptr->wr_error;
+ }
- 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);
+ if(fsp->is_directory) {
+ /*
+ * Special case - close NT SMB directory
+ * handle.
+ */
+ DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
+ close_directory(fsp);
+ } else {
+ /*
+ * Close ordinary file.
+ */
+ mtime = make_unix_date3(inbuf+smb_vwv1);
+
+ /* try and set the date */
+ set_filetime(conn, fsp->fsp_name,mtime);
+
+ DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
+ fsp->fd_ptr->fd, fsp->fnum,
+ conn->num_files_open));
+
+ close_file(fsp,True);
+ }
+
+ /* We have a cached error */
+ if(eclass || err)
+ return(ERROR(eclass,err));
+
+ 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 dum_size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
- int outsize = 0;
- int startpos;
- char *data;
- time_t mtime;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
-
- 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(fnum,cnum,numtowrite,startpos))
- return(ERROR(ERRDOS,ERRlock));
+ size_t numtowrite;
+ ssize_t nwritten = -1;
+ int outsize = 0;
+ SMB_OFF_T startpos;
+ char *data;
+ time_t mtime;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(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,numtowrite,startpos, F_WRLCK))
+ return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
+ seek_file(fsp,startpos);
- nwritten = write_file(fnum,data,numtowrite);
-
- close_file(fnum);
+ nwritten = write_file(fsp,data,numtowrite);
- set_filetime(Files[fnum].name,mtime);
+ set_filetime(conn, fsp->fsp_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));
+ close_file(fsp,True);
+
+ DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
+ fsp->fnum, numtowrite, nwritten,
+ conn->num_files_open));
- if (nwritten <= 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (nwritten <= 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
- outsize = set_message(outbuf,1,0,True);
+ outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,nwritten);
- return(outsize);
+ SSVAL(outbuf,smb_vwv0,nwritten);
+ 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_OFF_T count,offset;
+ int eclass;
+ uint32 ecode;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
+
+ count = IVAL(inbuf,smb_vwv1);
+ offset = IVAL(inbuf,smb_vwv3);
+
+ DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
+
+ if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode)) {
+ if((ecode == ERRlock) && 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))
+ return -1;
+ }
+ return (ERROR(eclass,ecode));
+ }
- if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
- return (ERROR(eclass,ecode));
-
- return(outsize);
+ return(outsize);
}
/****************************************************************************
reply to a unlock
****************************************************************************/
-int reply_unlock(char *inbuf,char *outbuf)
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int fnum,cnum;
int outsize = set_message(outbuf,0,0,True);
- uint32 count,offset;
+ SMB_OFF_T count,offset;
int eclass;
uint32 ecode;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
count = IVAL(inbuf,smb_vwv1);
offset = IVAL(inbuf,smb_vwv3);
- if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
+ if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
return (ERROR(eclass,ecode));
- DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd,fnum,cnum,offset,count));
+ DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
+ fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count ) );
return(outsize);
}
@@ -2051,21 +2555,24 @@ int reply_unlock(char *inbuf,char *outbuf)
/****************************************************************************
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;
- 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"));
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
+
+ conn->used = False;
- return outsize;
+ close_cnum(conn,vuid);
+
+ return outsize;
}
@@ -2073,254 +2580,218 @@ 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);
-
- cnum = SVAL(inbuf,smb_tid);
-
- 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);
+ 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);
+
+ /* 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);
- send_smb(Client,outbuf);
- }
+ send_smb(Client,outbuf);
+ }
- DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
+ DEBUG(3,("echo %d times\n", smb_reverb));
- return -1;
+ 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++;
- }
+ pstring fname;
+ pstring fname2;
+ int outsize = 0;
+ files_struct *fsp;
+
+ *fname = *fname2 = 0;
+
+ if (!CAN_PRINT(conn))
+ return(ERROR(ERRDOS,ERRnoaccess));
- if (strlen(s) > 10) s[10] = 0;
+ {
+ pstring s;
+ char *p;
+ pstrcpy(s,smb_buf(inbuf)+1);
+ p = s;
+ while (*p) {
+ if (!(isalnum((int)*p) || strchr("._-",*p)))
+ *p = 'X';
+ p++;
+ }
- sprintf(fname,"%s.XXXXXX",s);
- }
+ if (strlen(s) > 10) s[10] = 0;
- fnum = find_free_file();
- if (fnum < 0)
- return(ERROR(ERRSRV,ERRnofids));
+ slprintf(fname,sizeof(fname)-1, "%s.XXXXXX",s);
+ }
- strcpy(fname2,(char *)mktemp(fname));
+ fsp = file_new();
+ if (!fsp)
+ return(ERROR(ERRSRV,ERRnofids));
+
+ pstrcpy(fname2,(char *)mktemp(fname));
- if (!check_name(fname2,cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
+ if (!check_name(fname2,conn)) {
+ file_free(fsp);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
- open_file(fnum,cnum,fname2,O_WRONLY | O_CREAT | O_TRUNC,
- unix_mode(cnum,0));
+ /* Open for exclusive use, write only. */
+ open_file_shared(fsp,conn,fname2,
+ (DENY_ALL<<4)|1, 0x12, unix_mode(conn,0),
+ 0, NULL, NULL);
- if (!Files[fnum].open)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (!fsp->open) {
+ file_free(fsp);
+ 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);
+ /* force it to be a print file */
+ fsp->print_file = True;
- 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 %s fd=%d fnum=%d\n",
+ fname2, fsp->fd_ptr->fd, fsp->fnum));
+
+ 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);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
- if (!CAN_PRINT(cnum))
- return(ERROR(ERRDOS,ERRnoaccess));
+ if (!CAN_PRINT(conn))
+ return(ERROR(ERRDOS,ERRnoaccess));
- close_file(fnum);
+ DEBUG(3,("printclose fd=%d fnum=%d\n",
+ fsp->fd_ptr->fd,fsp->fnum));
- DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd,fnum,cnum));
-
- return(outsize);
+ close_file(fsp,True);
+
+ 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
-
- SSVAL(outbuf,smb_vwv0,0);
- SSVAL(outbuf,smb_vwv1,0);
- CVAL(smb_buf(outbuf),0) = 1;
- SSVAL(smb_buf(outbuf),1,0);
+ int outsize = set_message(outbuf,2,3,True);
+ int max_count = SVAL(inbuf,smb_vwv0);
+ int start_index = SVAL(inbuf,smb_vwv1);
+
+ /* 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))
+ return(ERROR(ERRDOS,ERRnoaccess));
+
+ 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;
-
- 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));
+ DEBUG(3,("printqueue start_index=%d max_count=%d\n",
+ start_index, max_count));
- {
- 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 = get_printqueue(SNUM(conn), 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,printjob_encode(SNUM(conn),
+ queue[i].job));
+ SIVAL(p,7,queue[i].size);
+ CVAL(p,11) = 0;
+ StrnCpy(p+12,queue[i].user,16);
+ 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);
+ if (queue) free(queue);
- DEBUG(3,("%d entries returned in queue\n",count));
- }
+ DEBUG(3,("%d entries returned in queue\n",count));
+ }
- return(outsize);
+ 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);
- cnum = SVAL(inbuf,smb_tid);
-
- if (!CAN_PRINT(cnum))
+ if (!CAN_PRINT(conn))
return(ERROR(ERRDOS,ERRnoaccess));
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
numtowrite = SVAL(smb_buf(inbuf),1);
data = smb_buf(inbuf) + 3;
- if (write_file(fnum,data,numtowrite) != numtowrite)
+ if (write_file(fsp,data,numtowrite) != numtowrite)
return(UNIXERROR(ERRDOS,ERRnoaccess));
- DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
+ DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
return(outsize);
}
@@ -2329,59 +2800,202 @@ int reply_printwrite(char *inbuf,char *outbuf)
/****************************************************************************
reply to a mkdir
****************************************************************************/
-int reply_mkdir(char *inbuf,char *outbuf)
+int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
pstring directory;
- int cnum;
int outsize,ret= -1;
+ BOOL bad_path = False;
+
+ pstrcpy(directory,smb_buf(inbuf) + 1);
+ unix_convert(directory,conn,0,&bad_path,NULL);
- 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 (check_name(directory, conn))
+ ret = dos_mkdir(directory,unix_mode(conn,aDIR));
if (ret < 0)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
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));
-
+
+ DEBUG( 3, ( "mkdir %s ret=%d\n", directory, ret ) );
+
return(outsize);
}
+/****************************************************************************
+Static function used by reply_rmdir to delete an entire directory
+tree recursively.
+****************************************************************************/
+static BOOL recursive_rmdir(char *directory)
+{
+ char *dname = NULL;
+ BOOL ret = False;
+ void *dirptr = OpenDir(NULL, 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(dos_lstat(fullname, &st) != 0)
+ {
+ ret = True;
+ break;
+ }
+
+ if(st.st_mode & S_IFDIR)
+ {
+ if(recursive_rmdir(fullname)!=0)
+ {
+ ret = True;
+ break;
+ }
+ if(dos_rmdir(fullname) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ else if(dos_unlink(fullname) != 0)
+ {
+ ret = True;
+ break;
+ }
+ }
+ CloseDir(dirptr);
+ return ret;
+}
/****************************************************************************
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;
+
+ pstrcpy(directory,smb_buf(inbuf) + 1);
+ unix_convert(directory,conn, NULL,&bad_path,NULL);
- cnum = SVAL(inbuf,smb_tid);
- strcpy(directory,smb_buf(inbuf) + 1);
- unix_convert(directory,cnum);
-
- if (check_name(directory,cnum))
+ if (check_name(directory,conn))
{
+
dptr_closepath(directory,SVAL(inbuf,smb_pid));
- ok = (sys_rmdir(directory) == 0);
+ ok = (dos_rmdir(directory) == 0);
+ if(!ok && (errno == ENOTEMPTY) && 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(dos_lstat(fullname, &st) != 0)
+ break;
+ if(st.st_mode & S_IFDIR)
+ {
+ if(lp_recursive_veto_delete(SNUM(conn)))
+ {
+ if(recursive_rmdir(fullname) != 0)
+ break;
+ }
+ if(dos_rmdir(fullname) != 0)
+ break;
+ }
+ else if(dos_unlink(fullname) != 0)
+ break;
+ }
+ CloseDir(dirptr);
+ /* Retry the rmdir */
+ ok = (dos_rmdir(directory) == 0);
+ }
+ else
+ CloseDir(dirptr);
+ }
+ else
+ errno = ENOTEMPTY;
+ }
+
if (!ok)
- DEBUG(3,("couldn't remove directory %s : %s\n",
+ DEBUG(3,("couldn't remove directory %s : %s\n",
directory,strerror(errno)));
}
if (!ok)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
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 ) );
return(outsize);
}
@@ -2401,21 +3015,21 @@ static BOOL resolve_wildcards(char *name1,char *name2)
if (!name1 || !name2) return(False);
- strcpy(root1,name1);
- strcpy(root2,name2);
+ fstrcpy(root1,name1);
+ fstrcpy(root2,name2);
p = strrchr(root1,'.');
if (p) {
*p = 0;
- strcpy(ext1,p+1);
+ fstrcpy(ext1,p+1);
} else {
- strcpy(ext1,"");
+ fstrcpy(ext1,"");
}
p = strrchr(root2,'.');
if (p) {
*p = 0;
- strcpy(ext2,p+1);
+ fstrcpy(ext2,p+1);
} else {
- strcpy(ext2,"");
+ fstrcpy(ext2,"");
}
p = root1;
@@ -2442,10 +3056,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,121 +3068,234 @@ 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;
+ SMB_STRUCT_STAT sbuf;
- if (!CAN_WRITE(cnum)) return(False);
+ if (!CAN_WRITE(conn)) return(False);
- if (sys_lstat(fname,&sbuf) != 0) return(False);
- if (!check_file_sharing(cnum,fname)) return(False);
+ if (dos_lstat(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)
+int rename_internals(connection_struct *conn,
+ char *inbuf, char *outbuf, 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);
-
- 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);
-
- has_wild = strchr(mask,'*') || strchr(mask,'?');
-
- 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;
-
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ pstring directory;
+ pstring mask;
+ pstring newname_last_component;
+ char *p;
+ BOOL has_wild;
+ BOOL bad_path1 = False;
+ BOOL bad_path2 = False;
+ int count=0;
+ int error = ERRnoaccess;
+ BOOL exists=False;
+
+ *directory = *mask = 0;
+
+ unix_convert(name,conn,0,&bad_path1,NULL);
+ unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
+
+ /*
+ * 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(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. */
+ }
- if (dirptr)
- {
- error = ERRbadfile;
+ if (is_mangled(mask))
+ check_mangled_cache( mask );
+
+ has_wild = strchr(mask,'*') || strchr(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(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(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
+ * file_exist().
+ */
+ if(resolve_wildcards(directory,newname) &&
+ can_rename(directory,conn) &&
+ !dos_rename(directory,newname))
+ count++;
+ } else {
+ if (resolve_wildcards(directory,newname) &&
+ can_rename(directory,conn) &&
+ !file_exist(newname,NULL) &&
+ !dos_rename(directory,newname))
+ count++;
+ }
- if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
+ directory,newname));
+
+ if (!count) exists = file_exist(directory,NULL);
+ if (!count && exists && file_exist(newname,NULL)) {
+ exists = True;
+ error = 183;
+ }
+ } 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 = ERRbadfile;
+
+ if (strequal(mask,"????????.???"))
+ pstrcpy(mask,"*");
+
+ while ((dname = ReadDirName(dirptr))) {
+ pstring fname;
+ pstrcpy(fname,dname);
+
+ if(!mask_match(fname, mask, case_sensitive, False))
+ continue;
+
+ error = ERRnoaccess;
+ 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 && file_exist(destname,NULL)) {
+ DEBUG(6,("file_exist %s\n", destname));
+ error = 183;
+ continue;
+ }
+
+ if (!dos_rename(fname,destname))
+ count++;
+ DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
+ }
+ CloseDir(dirptr);
+ }
+ }
+
+ if (count == 0) {
+ if (exists)
+ return(ERROR(ERRDOS,error));
+ else {
+ if((errno == ENOENT) && (bad_path1 || bad_path2)) {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,error));
+ }
+ }
+
+ return 0;
+}
- while ((dname = ReadDirName(dirptr)))
- {
- pstring fname;
- strcpy(fname,dname);
-
- if(!mask_match(fname, mask, case_sensitive, False)) continue;
+/****************************************************************************
+ Reply to a mv.
+****************************************************************************/
- error = ERRnoaccess;
- sprintf(fname,"%s/%s",directory,dname);
- if (!can_rename(fname,cnum)) continue;
- strcpy(destname,newname);
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+ int outsize = 0;
+ pstring name;
+ pstring newname;
- if (!resolve_wildcards(fname,destname)) continue;
+ pstrcpy(name,smb_buf(inbuf) + 1);
+ pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
+
+ DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- 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);
- }
- }
-
- if (count == 0) {
- if (exists)
- return(ERROR(ERRDOS,error));
- else
- return(UNIXERROR(ERRDOS,error));
- }
-
- outsize = set_message(outbuf,0,0,True);
+ outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
+ if(outsize == 0)
+ outsize = set_message(outbuf,0,0,True);
return(outsize);
}
@@ -2576,60 +3303,65 @@ int reply_mv(char *inbuf,char *outbuf)
/*******************************************************************
copy a file as part of a reply_copy
******************************************************************/
-static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
+static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
int count,BOOL target_is_directory)
{
int Access,action;
- struct stat st;
+ SMB_STRUCT_STAT st;
int ret=0;
- int fnum1,fnum2;
+ files_struct *fsp1,*fsp2;
pstring dest;
- strcpy(dest,dest1);
+ pstrcpy(dest,dest1);
if (target_is_directory) {
char *p = strrchr(src,'/');
if (p)
p++;
else
p = src;
- strcat(dest,"/");
- strcat(dest,p);
+ pstrcat(dest,"/");
+ pstrcat(dest,p);
}
if (!file_exist(src,&st)) 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 = file_new();
+ if (!fsp1) return(False);
+ open_file_shared(fsp1,conn,src,(DENY_NONE<<4),
+ 1,0,0,&Access,&action);
- if (!Files[fnum1].open) return(False);
+ if (!fsp1->open) {
+ file_free(fsp1);
+ return(False);
+ }
if (!target_is_directory && count)
ofun = 1;
- fnum2 = find_free_file();
- if (fnum2<0) {
- close_file(fnum1);
- return(False);
+ fsp2 = file_new();
+ if (!fsp2) {
+ close_file(fsp1,False);
+ return(False);
}
- open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
- ofun,st.st_mode,&Access,&action);
+ open_file_shared(fsp2,conn,dest,(DENY_NONE<<4)|1,
+ ofun,st.st_mode,0,&Access,&action);
- if (!Files[fnum2].open) {
- close_file(fnum1);
+ if (!fsp2->open) {
+ close_file(fsp1,False);
+ file_free(fsp2);
return(False);
}
if ((ofun&3) == 1) {
- lseek(Files[fnum2].fd,0,SEEK_END);
+ sys_lseek(fsp2->fd_ptr->fd,0,SEEK_END);
}
if (st.st_size)
- ret = transfer_file(Files[fnum1].fd,Files[fnum2].fd,st.st_size,NULL,0,0);
+ ret = transfer_file(fsp1->fd_ptr->fd,
+ fsp2->fd_ptr->fd,st.st_size,NULL,0,0);
- close_file(fnum1);
- close_file(fnum2);
+ close_file(fsp1,False);
+ close_file(fsp2,False);
return(ret == st.st_size);
}
@@ -2639,11 +3371,10 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
/****************************************************************************
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;
@@ -2655,24 +3386,24 @@ int reply_copy(char *inbuf,char *outbuf)
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;
*directory = *mask = 0;
- cnum = SVAL(inbuf,smb_tid);
-
- strcpy(name,smb_buf(inbuf));
- strcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
+ pstrcpy(name,smb_buf(inbuf));
+ pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
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));
}
- unix_convert(name,cnum);
- unix_convert(newname,cnum);
+ unix_convert(name,conn,0,&bad_path1,NULL);
+ unix_convert(newname,conn,0,&bad_path2,NULL);
target_is_directory = directory_exist(newname,NULL);
@@ -2692,24 +3423,24 @@ int reply_copy(char *inbuf,char *outbuf)
p = strrchr(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);
+ check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(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,
+ copy_file(directory,newname,conn,ofun,
count,target_is_directory)) count++;
if (!count) exists = file_exist(directory,NULL);
} else {
@@ -2717,28 +3448,28 @@ int reply_copy(char *inbuf,char *outbuf)
char *dname;
pstring destname;
- if (check_name(directory,cnum))
- dirptr = OpenDir(directory);
+ if (check_name(directory,conn))
+ dirptr = OpenDir(conn, directory, True);
if (dirptr)
{
error = ERRbadfile;
if (strequal(mask,"????????.???"))
- strcpy(mask,"*");
+ pstrcpy(mask,"*");
while ((dname = ReadDirName(dirptr)))
{
pstring fname;
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
if(!mask_match(fname, mask, case_sensitive, False)) 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,
+ copy_file(directory,newname,conn,ofun,
count,target_is_directory)) count++;
DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
@@ -2750,7 +3481,14 @@ int reply_copy(char *inbuf,char *outbuf)
if (exists)
return(ERROR(ERRDOS,error));
else
+ {
+ if((errno == ENOENT) && (bad_path1 || bad_path2))
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
return(UNIXERROR(ERRDOS,error));
+ }
}
outsize = set_message(outbuf,1,0,True);
@@ -2759,139 +3497,225 @@ int reply_copy(char *inbuf,char *outbuf)
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;
- cnum = SVAL(inbuf,smb_tid);
-
- snum = Connections[cnum].service;
+ snum = SNUM(conn);
if (!CAN_SETDIR(snum))
return(ERROR(ERRDOS,ERRnoaccess));
- strcpy(newdir,smb_buf(inbuf) + 1);
+ pstrcpy(newdir,smb_buf(inbuf) + 1);
strlower(newdir);
- 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 = directory_exist(newdir,NULL);
+ if (ok) {
+ string_set(&conn->connectpath,newdir);
+ }
+ }
if (!ok)
- return(ERROR(ERRDOS,ERRbadpath));
+ return(ERROR(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));
+
return(outsize);
}
-
/****************************************************************************
reply to a lockingX request
****************************************************************************/
-int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_lockingX(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);
- uint16 locktype = SVAL(inbuf,smb_vwv3);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv2);
+ unsigned char locktype = CVAL(inbuf,smb_vwv3);
+#if 0
+ unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+#endif
uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
uint16 num_locks = SVAL(inbuf,smb_vwv7);
- uint32 count, offset;
-
- int cnum;
+ SMB_OFF_T count = 0, offset = 0;
+ int32 lock_timeout = IVAL(inbuf,smb_vwv4);
int i;
char *data;
uint32 ecode=0, dummy2;
- int outsize, eclass=0, dummy1;
+ int eclass=0, dummy1;
+ BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
+
+ 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))
+ {
+ int token;
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+
+ DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
+ fsp->fnum));
+ /*
+ * Make sure we have granted an oplock on this file.
+ */
+ if(!fsp->granted_oplock)
+ {
+ DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file.\n", fsp->fnum));
+ return ERROR(ERRDOS,ERRlock);
+ }
- cnum = SVAL(inbuf,smb_tid);
+ /* Remove the oplock flag from the sharemode. */
+ lock_share_entry(fsp->conn, dev, inode, &token);
+ if(remove_share_oplock(fsp, token)==False) {
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
+
+ unlock_share_entry(fsp->conn, dev, inode, token);
+ } else {
+ unlock_share_entry(fsp->conn, dev, inode, token);
+
+ /* Clear the granted flag and return. */
+ fsp->granted_oplock = False;
+ }
+
+ /* 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) ));
+ return -1;
+ }
+ }
- 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))
+ if(!large_file_format) {
+ count = IVAL(data,SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data,SMB_LKOFF_OFFSET(i));
+ }
+#ifdef LARGE_SMB_OFF_T
+ else {
+ count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
+ offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name ));
+
+ if(!do_unlock(fsp,conn,count,offset,&eclass, &ecode))
return ERROR(eclass,ecode);
}
+ /* Setup the timeout in seconds. */
+ lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
+
/* Now do any requested locks */
- data += 10*num_ulocks;
+ 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++) {
- count = IVAL(data,SMB_LKLEN_OFFSET(i));
- offset = IVAL(data,SMB_LKOFF_OFFSET(i));
- if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
+ if(!large_file_format) {
+ count = IVAL(data,SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data,SMB_LKOFF_OFFSET(i));
+ }
+#ifdef LARGE_SMB_OFF_T
+ else {
+ count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
+ offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
+ (double)offset, (double)count, fsp->fsp_name ));
+
+ if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK),
+ &eclass, &ecode)) {
+ if((ecode == ERRlock) && (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))
+ 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) {
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);
+ if(!large_file_format) {
+ count = IVAL(data,SMB_LKLEN_OFFSET(i));
+ offset = IVAL(data,SMB_LKOFF_OFFSET(i));
+ }
+#ifdef LARGE_SMB_OFF_T
+ else {
+ count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
+ offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
+ ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
+ }
+#endif /* LARGE_SMB_OFF_T */
+
+ do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
}
return ERROR(eclass,ecode);
}
- outsize = set_message(outbuf,2,0,True);
+ 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));
-
- chain_fnum = fnum;
+ DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
+ fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
- if (smb_com2 != 0xFF)
- outsize += chain_reply(smb_com2,inbuf,inbuf+smb_off2+4,
- outbuf,outbuf+outsize,
- length,bufsize);
-
- chain_fnum = -1;
-
- return(outsize);
+ return chain_reply(inbuf,outbuf,length,bufsize);
}
/****************************************************************************
reply to a SMBreadbmpx (read block multiplex) request
****************************************************************************/
-int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
- int cnum,fnum;
- int nread = -1;
- int total_read;
+ ssize_t nread = -1;
+ ssize_t total_read;
char *data;
- int32 startpos;
- int outsize, mincount, maxcount;
+ SMB_OFF_T startpos;
+ int outsize;
+ size_t maxcount;
int max_per_packet;
- int tcount;
+ size_t tcount;
int pad;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
/* this function doesn't seem to work - disable by default */
if (!lp_readbmpx())
@@ -2899,19 +3723,15 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
outsize = set_message(outbuf,8,0,True);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_READ(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_READ(fsp);
+ CHECK_ERROR(fsp);
startpos = IVAL(inbuf,smb_vwv1);
maxcount = SVAL(inbuf,smb_vwv3);
- mincount = SVAL(inbuf,smb_vwv4);
data = smb_buf(outbuf);
- pad = ((int)data)%4;
+ pad = ((long)data)%4;
if (pad) pad = 4 - pad;
data += pad;
@@ -2919,19 +3739,19 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
tcount = maxcount;
total_read = 0;
- if (is_locked(fnum,cnum,maxcount,startpos))
+ if (is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
return(ERROR(ERRDOS,ERRlock));
do
{
- int N = MIN(max_per_packet,tcount-total_read);
+ size_t N = MIN(max_per_packet,tcount-total_read);
- nread = read_file(fnum,data,startpos,N,N,-1,False);
+ nread = read_file(fsp,data,startpos,N);
if (nread <= 0) nread = 0;
- if (nread < N)
- tcount = total_read + nread;
+ if (nread < (ssize_t)N)
+ tcount = total_read + nread;
set_message(outbuf,8,nread,False);
SIVAL(outbuf,smb_vwv0,startpos);
@@ -2944,30 +3764,29 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
total_read += nread;
startpos += nread;
}
- while (total_read < tcount);
+ while (total_read < (ssize_t)tcount);
return(-1);
}
-
/****************************************************************************
reply to a SMBwritebmpx (write block multiplex primary) request
****************************************************************************/
-int reply_writebmpx(char *inbuf,char *outbuf)
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
int outsize = 0;
- int32 startpos;
- int tcount, write_through, smb_doff;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
char *data;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
+ CHECK_ERROR(fsp);
tcount = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv3);
@@ -2981,41 +3800,41 @@ int reply_writebmpx(char *inbuf,char *outbuf)
not an SMBwritebmpx - set this up now so we don't forget */
CVAL(outbuf,smb_com) = SMBwritec;
- if (is_locked(fnum,cnum,tcount,startpos))
+ if (is_locked(fsp,conn,tcount,startpos,F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- seek_file(fnum,startpos);
- nwritten = write_file(fnum,data,numtowrite);
+ seek_file(fsp,startpos);
+ nwritten = write_file(fsp,data,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(nwritten < (ssize_t)numtowrite)
return(UNIXERROR(ERRHRD,ERRdiskfull));
/* 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)
+ 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)
{
- 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;
+ 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;
+ fsp->wbmpx_ptr = wbms;
+ }
/* We are returning successfully, set the message type back to
SMBwritebmpx */
@@ -3025,9 +3844,9 @@ int reply_writebmpx(char *inbuf,char *outbuf)
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));
-
+ DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
+ fsp->fnum, numtowrite, nwritten ) );
+
if (write_through && tcount==nwritten) {
/* we need to send both a primary and a secondary response */
smb_setlen(outbuf,outsize - 4);
@@ -3046,21 +3865,22 @@ int reply_writebmpx(char *inbuf,char *outbuf)
/****************************************************************************
reply to a SMBwritebs (write block multiplex secondary) request
****************************************************************************/
-int reply_writebs(char *inbuf,char *outbuf)
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,numtowrite,fnum;
- int nwritten = -1;
+ size_t numtowrite;
+ ssize_t nwritten = -1;
int outsize = 0;
- int32 startpos;
- int tcount, write_through, smb_doff;
+ SMB_OFF_T startpos;
+ size_t tcount;
+ BOOL write_through;
+ int smb_doff;
char *data;
write_bmpx_struct *wbms;
- BOOL send_response = False;
-
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
- CHECK_FNUM(fnum,cnum);
- CHECK_WRITE(fnum);
+ BOOL send_response = False;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+ CHECK_FSP(fsp,conn);
+ CHECK_WRITE(fsp);
tcount = SVAL(inbuf,smb_vwv1);
startpos = IVAL(inbuf,smb_vwv2);
@@ -3074,7 +3894,7 @@ int reply_writebs(char *inbuf,char *outbuf)
/* This fd should have an auxiliary struct attached,
check that it does */
- wbms = Files[fnum].wbmpx_ptr;
+ wbms = fsp->wbmpx_ptr;
if(!wbms) return(-1);
/* If write through is set we can return errors, else we must
@@ -3085,38 +3905,40 @@ int reply_writebs(char *inbuf,char *outbuf)
if(wbms->wr_discard)
return -1; /* Just discard the packet */
- seek_file(fnum,startpos);
- nwritten = write_file(fnum,data,numtowrite);
+ seek_file(fsp,startpos);
+ nwritten = write_file(fsp,data,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 (nwritten < (ssize_t)numtowrite)
+ {
+ if(write_through)
{
- 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));
+ /* We are returning an error - we can delete the aux struct */
+ if (wbms) free((char *)wbms);
+ fsp->wbmpx_ptr = NULL;
+ return(ERROR(ERRHRD,ERRdiskfull));
}
+ return(CACHE_ERROR(wbms,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 (write_through) {
- outsize = set_message(outbuf,1,0,True);
- SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
- send_response = True;
- }
-
- free((char *)wbms);
- Files[fnum].wbmpx_ptr = NULL;
+ 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)
return(outsize);
@@ -3127,19 +3949,16 @@ int reply_writebs(char *inbuf,char *outbuf)
/****************************************************************************
reply to a SMBsetattrE
****************************************************************************/
-int reply_setattrE(char *inbuf,char *outbuf)
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
- int cnum,fnum;
struct utimbuf unix_times;
int outsize = 0;
+ files_struct *fsp = file_fsp(inbuf,smb_vwv0);
outsize = set_message(outbuf,0,0,True);
- cnum = SVAL(inbuf,smb_tid);
- fnum = GETFNUM(inbuf,smb_vwv0);
-
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
/* Convert the DOS times into unix times. Ignore create
time as UNIX can't set this.
@@ -3147,11 +3966,33 @@ int reply_setattrE(char *inbuf,char *outbuf)
unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
+ /*
+ * Patch from Ray Frush <frush@engr.colostate.edu>
+ * Sometimes times are sent as zero - ignore them.
+ */
+
+ 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" );
+ }
+ 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;
+ }
+
/* Set the date on this file */
- if(sys_utime(Files[fnum].name, &unix_times))
+ if(file_utime(conn, fsp->fsp_name, &unix_times))
return(ERROR(ERRDOS,ERRnoaccess));
- DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
+ fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
return(outsize);
}
@@ -3160,31 +4001,28 @@ int reply_setattrE(char *inbuf,char *outbuf)
/****************************************************************************
reply to a SMBgetattrE
****************************************************************************/
-int reply_getattrE(char *inbuf,char *outbuf)
+int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_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);
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);
+ CHECK_ERROR(fsp);
/* Do an fstat on this file */
- if(fstat(Files[fnum].fd, &sbuf))
+ if(sys_fstat(fsp->fd_ptr->fd, &sbuf))
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 +4032,12 @@ int reply_getattrE(char *inbuf,char *outbuf)
}
else
{
- SIVAL(outbuf,smb_vwv6,sbuf.st_size);
+ SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
SIVAL(outbuf,smb_vwv8,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));
return(outsize);
}
-
-
-
-
-
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 5d8facef33f..fb97cf83800 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,14 @@
*/
#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;
@@ -52,4249 +37,682 @@ int last_message = -1;
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;
+#ifdef WITH_DFS
+extern int dcelogin_atmost_once;
+#endif /* WITH_DFS */
-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;
extern fstring remote_machine;
-
-
-/* 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;
-
+extern pstring OriginalDir;
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
+ when exiting, take the whole family
****************************************************************************/
-mode_t unix_mode(int cnum,int dosmode)
+static void *dflt_sig(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);
+ exit_server("caught signal");
+ return NULL;
}
-
/****************************************************************************
- change a unix mode to a dos mode
-****************************************************************************/
-int dos_mode(int cnum,char *path,struct stat *sbuf)
+ Send a SIGTERM to our process group.
+*****************************************************************************/
+static void killkids(void)
{
- 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)
-{
- 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));
+ if(am_parent) kill(0,SIGTERM);
}
/****************************************************************************
-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)
-{
- pstring tmpname;
-
- if (is_8_3(name2))
- return(False);
-
- strcpy(tmpname,name2);
- mangle_name_83(tmpname);
-
- return(strequal(name1,tmpname));
-}
-
-
-/****************************************************************************
-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,int snum,BOOL docache)
-{
- 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);
-}
-
-/****************************************************************************
-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
-****************************************************************************/
-BOOL unix_convert(char *name,int cnum)
-{
- 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;
-
- *rest = 0;
-
- /* remember the rest of the pathname so it can be restored
- later */
- if (end) strcpy(rest,end+1);
-
-
- /* 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);
-}
-
-
-
-
-#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
+ open the socket communication
****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
+static BOOL open_sockets_inetd(void)
{
- 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);
+ extern int Client;
- 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)
-****************************************************************************/
-static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize)
-{
- 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 */
+ Client = 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 */
-
-
-/****************************************************************************
-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
-}
-
-
-/****************************************************************************
-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));
-}
-
+ set_socket_options(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
-
-/****************************************************************************
-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;
- }
+ return True;
}
/****************************************************************************
-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;
+ extern int Client;
+ int num_interfaces = iface_count();
+ int fd_listenset[FD_SETSIZE];
+ fd_set listen_set;
+ int s;
+ int i;
- 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
-
-
- 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++;
- }
- 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;
+ if (!is_daemon) {
+ return open_sockets_inetd();
}
- }
-#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);
+ if(s == -1)
+ return False;
+ /* ready to listen */
+ 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()));
+ if (s == -1)
+ return(False);
+
+ /* ready to listen */
+ 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);
+ }
+
+ /* 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;
+
+ memcpy((char *)&lfds, (char *)&listen_set,
+ sizeof(listen_set));
+
+ num = sys_select(256,&lfds,NULL);
+
+ if (num == -1 && errno == EINTR)
+ continue;
+
+ /* Find the sockets that are read-ready -
+ accept on these. */
+ for( ; num > 0; num--) {
+ struct sockaddr addr;
+ int 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;
+ }
+ }
+
+ Client = accept(s,&addr,&in_addrlen);
+
+ if (Client == -1 && errno == EINTR)
+ continue;
+
+ if (Client == -1) {
+ DEBUG(0,("open_sockets: accept: %s\n",
+ strerror(errno)));
+ continue;
+ }
+
+ if (Client != -1 && 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(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
+
+ /* Reset global variables in util.c so
+ that client substitutions will be
+ done correctly in the process. */
+ reset_globals_after_fork();
+
+ /*
+ * Ensure this child has kernel oplock
+ * capabilities, but not it's children.
+ */
+ set_process_capability(KERNEL_OPLOCK_CAPABILITY, True);
+ set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
+
+ return True;
+ }
+ /* The parent doesn't need this socket */
+ close(Client);
+
+ /* 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;
- }
+ BOOL ret;
- 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 (lp_loaded()) {
+ pstring fname;
+ pstrcpy(fname,lp_configfile());
+ if (file_exist(fname,NULL) && !strcsequal(fname,servicesf)) {
+ pstrcpy(servicesf,fname);
+ test = False;
+ }
}
-
- if (access_allowed == AREAD)
- flags = O_RDONLY;
-
- 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;
- }
+ reopen_logs();
- Files[fnum].share_mode = (deny_mode<<4) | open_mode;
- Files[fnum].share_pending = True;
+ if (test && !lp_file_list_changed())
+ return(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;
- }
+ lp_killunused(conn_snum_used);
- if (!share_pid)
- share_mode_pending = True;
-
- if ((flags2&O_TRUNC) && file_existed)
- truncate_unless_locked(fnum,cnum);
- }
-}
-
-
-
-/*******************************************************************
-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;
- }
- }
-}
-
-
-/****************************************************************************
-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;
+ ret = lp_load(servicesf,False,False,True);
- Files[fnum].pos = lseek(Files[fnum].fd,pos+offset,SEEK_SET) - offset;
- return(Files[fnum].pos);
-}
+ load_printers();
-/****************************************************************************
-read from a file
-****************************************************************************/
-int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact)
-{
- int ret=0;
+ /* perhaps the config filename is now set */
+ if (!test)
+ reload_services(True);
- if (!Files[fnum].can_write)
- {
- ret = read_predict(Files[fnum].fd,
- pos,
- data,
- NULL,
- maxcnt);
+ reopen_logs();
- data += ret;
- maxcnt -= ret;
- mincnt = MAX(mincnt-ret,0);
- pos += ret;
- }
+ load_interfaces();
-#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;
+ extern int Client;
+ if (Client != -1) {
+ set_socket_options(Client,"SO_KEEPALIVE");
+ set_socket_options(Client,user_socket_options);
+ }
}
- }
-#endif
- if (maxcnt <= 0)
- return(ret);
+ reset_mangled_cache();
- 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);
+ /* this forces service parameters to be flushed */
+ become_service(NULL,True);
- return(ret);
+ return(ret);
}
-/****************************************************************************
-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));
-}
-
-
-static int old_umask = 022;
-
-/****************************************************************************
-load parameters specific to a connection/service
-****************************************************************************/
-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);
-}
-
/****************************************************************************
- become the specified uid
+this prevents zombie child processes
****************************************************************************/
-static BOOL become_uid(int uid)
-{
- 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
-
-#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);
-}
-
+BOOL reload_after_sighup = False;
-/****************************************************************************
- become the specified gid
-****************************************************************************/
-static BOOL become_gid(int gid)
+static void sig_hup(int sig)
{
- 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);
-}
+ BlockSignals(True,SIGHUP);
+ DEBUG(0,("Got SIGHUP\n"));
+ /*
+ * Fix from <branko.cibej@hermes.si> here.
+ * We used to reload in the signal handler - this
+ * is a *BIG* no-no.
+ */
-/****************************************************************************
- become the specified uid and gid
-****************************************************************************/
-static BOOL become_id(int uid,int gid)
-{
- return(become_gid(gid) && become_uid(uid));
+ reload_after_sighup = True;
+ BlockSignals(False,SIGHUP);
}
-/****************************************************************************
-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 )
-{
- 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);
-#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);
-}
-
-
-/****************************************************************************
- create an error packet from a cached error.
-****************************************************************************/
-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[] =
-{
- {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}
-};
-
-
-/****************************************************************************
- 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++;
- }
- }
-
- 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
-****************************************************************************/
-static int sig_cld()
-{
- 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
-
- /* 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
-
-#ifndef USE_WAITPID
- while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0);
-#endif
- depth--;
- BlockSignals(False);
- return 0;
-}
-#endif
-
-/****************************************************************************
- 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)
+static BOOL dump_core(void)
{
- 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
-
- /* open an incoming socket */
- s = open_socket_in(SOCK_STREAM, port, 0);
- if (s == -1)
- return(False);
-
- /* ready to listen */
- if (listen(s, 5) == -1)
+ char *p;
+ pstring dname;
+ pstrcpy(dname,debugf);
+ 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
{
- DEBUG(0,("listen: %s",strerror(errno)));
- close(s);
- return False;
+ 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));
}
-
- /* 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);
-
- if (Client == -1 && errno == EINTR)
- continue;
-
- if (Client == -1)
- {
- DEBUG(0,("accept: %s",strerror(errno)));
- return False;
- }
-
-#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
- }
- }
- 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();
-
- set_socket_options(Client,"SO_KEEPALIVE");
- set_socket_options(Client,user_socket_options);
- }
-
- return True;
-}
-
-
-/****************************************************************************
-check if a snum is in use
-****************************************************************************/
-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)
-{
- BOOL ret;
-
- if (lp_loaded())
- {
- pstring fname;
- strcpy(fname,lp_configfile());
- if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
- {
- strcpy(servicesf,fname);
- test = False;
- }
- }
-
- reopen_logs();
-
- if (test && !lp_file_list_changed())
- return(True);
-
- lp_killunused(snum_used);
-
- ret = lp_load(servicesf,False);
-
- /* perhaps the config filename is now set */
- if (!test)
- reload_services(True);
- 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);
+ DEBUG(0,("Dumping core in %s\n",dname));
+ abort();
+ return(True);
}
-
-
-
-/****************************************************************************
-this prevents zombie child processes
-****************************************************************************/
-static int sig_hup()
-{
- 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;
-}
/****************************************************************************
- make a connection to a service
+exit the server
****************************************************************************/
-int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid)
+void exit_server(char *reason)
{
- 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);
+ static int firsttime=1;
+ extern char *last_inbuf;
- /* 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));
+ if (!firsttime) exit(0);
+ firsttime = 0;
- /* 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;
- }
+ unbecome_user();
+ DEBUG(2,("Closing connections\n"));
- /* 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);
+ conn_close_all();
-#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)));
+#ifdef WITH_DFS
+ if (dcelogin_atmost_once) {
+ dfs_unlogin();
}
- else
- DEBUG(1,("Couldn't find group %s\n",lp_force_group(snum)));
- }
#endif
- 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);
- }
+ 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
+ }
- 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()));
- }
+ locking_end();
- return(cnum);
+ DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
+ exit(0);
}
-/****************************************************************************
- 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);
-}
/****************************************************************************
- 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.
+ initialise connect, service and file structs
****************************************************************************/
-static int find_free_connection(int hash )
+static void init_structs(void )
{
- int i;
- BOOL used=False;
- hash = (hash % (MAX_CONNECTIONS-2))+1;
+ get_myname(myhostname,NULL);
- again:
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
- 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 (!*global_myname) {
+ char *p;
+ fstrcpy( global_myname, myhostname );
+ p = strchr( global_myname, '.' );
+ if (p)
+ *p = 0;
}
- i++;
- if (i == MAX_CONNECTIONS)
- i = 1;
- }
-
- if (!used)
- {
- used = !used;
- goto again;
- }
-
- DEBUG(1,("ERROR! Out of connection structures\n"));
- return(-1);
-}
-
-
-/****************************************************************************
-reply for the core protocol
-****************************************************************************/
-int reply_corep(char *outbuf)
-{
- int outsize = set_message(outbuf,1,0,True);
- Protocol = PROTOCOL_CORE;
+ strupper( global_myname );
- return outsize;
-}
+ conn_init();
+ file_init();
-/****************************************************************************
-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 */
+ /* for RPC pipes */
+ init_rpc_pipe_hnd();
- Protocol = PROTOCOL_COREPLUS;
+ /* for LSA handles */
+ init_lsa_policy_hnd();
- return outsize;
+ init_dptrs();
}
-
/****************************************************************************
-reply for the lanman 1.0 protocol
+usage on the program
****************************************************************************/
-int reply_lanman1(char *outbuf)
+static void usage(char *pname)
{
- 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
-
- 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));
-#endif
- }
+ DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
- 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);
-
- put_dos_date(outbuf,smb_vwv8,t);
-
- return (smb_len(outbuf)+4);
+ printf("Usage: %s [-D] [-p port] [-d debuglevel] ", pname);
+ printf("[-l log basename] [-s services file]\n" );
+ 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 append to log file (default)\n");
+ printf("\t-o overwrite log file, don't append\n");
+ printf("\n");
}
/****************************************************************************
-reply for the lanman 2.0 protocol
+ main program
****************************************************************************/
-int reply_lanman2(char *outbuf)
+ int main(int argc,char *argv[])
{
- 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));
+ extern BOOL append_log;
+ /* shall I run as a daemon */
+ BOOL is_daemon = False;
+ int port = SMB_PORT;
+ int opt;
+ extern char *optarg;
+
+#ifdef HAVE_SET_AUTH_PARAMETERS
+ set_auth_parameters(argc,argv);
#endif
- SIVAL(outbuf,smb_vwv6,getpid());
-
- Protocol = PROTOCOL_LANMAN2;
-
- 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));
+#ifdef HAVE_SETLUID
+ /* needed for SecureWare on SCO */
+ setluid(0);
#endif
- }
- 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);
+ append_log = True;
- return (smb_len(outbuf)+4);
-}
+ TimeInit();
-/****************************************************************************
-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();
+ pstrcpy(debugf,SMBLOGFILE);
- if (lp_security()>=SEC_USER) secword |= 1;
- if (doencrypt) secword |= 2;
+ pstrcpy(remote_machine, "smb");
- 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 */
+ setup_logging(argv[0],False);
- Protocol = PROTOCOL_NT1;
+ charset_initialise();
- 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));
+ /* make absolutely sure we run as root - to handle cases where people
+ are crazy enough to have it setuid */
+#ifdef HAVE_SETRESUID
+ setresuid(0,0,0);
+#else
+ setuid(0);
+ seteuid(0);
+ setuid(0);
+ seteuid(0);
#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();
+ fault_setup((void (*)(void *))exit_server);
+ CatchSignal(SIGTERM , SIGNAL_CAST dflt_sig);
- if (!OPEN_CNUM(cnum))
- {
- DEBUG(0,("Can't close cnum %d\n",cnum));
- return;
- }
+ /* we are never interested in SIGPIPE */
+ BlockSignals(True,SIGPIPE);
- 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))));
+ /* we want total control over the permissions on created files,
+ so set our umask to 0 */
+ umask(0);
- yield_connection(cnum,
- lp_servicename(SNUM(cnum)),
- lp_max_connections(SNUM(cnum)));
+ GetWd(OriginalDir);
- if (lp_status(SNUM(cnum)))
- yield_connection(cnum,"STATUS.",MAXSTATUS);
+ init_uid();
- 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);
+ /* this is for people who can't start the program correctly */
+ while (argc > 1 && (*argv[1] != '-')) {
+ argv++;
+ argc--;
}
- 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);
- }
+ while ( EOF != (opt = getopt(argc, argv, "O:i:l:s:d:Dp:h?Paof:")) )
+ switch (opt) {
+ case 'O':
+ pstrcpy(user_socket_options,optarg);
+ break;
- 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);
- }
+ case 'i':
+ pstrcpy(scope,optarg);
+ break;
- DEBUG(3,("Yield successful\n"));
+ case 'P':
+ {
+ extern BOOL passive;
+ passive = True;
+ }
+ break;
- fclose(f);
- return(True);
-}
+ case 's':
+ pstrcpy(servicesf,optarg);
+ break;
+ case 'l':
+ pstrcpy(debugf,optarg);
+ break;
-/****************************************************************************
-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;
+ case 'a':
+ append_log = True;
+ break;
- if (max_connections <= 0)
- return(True);
+ case 'o':
+ append_log = False;
+ break;
- DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
+ case 'D':
+ is_daemon = True;
+ break;
- strcpy(fname,lp_lockdir());
- standard_sub(cnum,fname);
- trim_string(fname,"","/");
+ case 'd':
+ if (*optarg == 'A')
+ DEBUGLEVEL = 10000;
+ else
+ DEBUGLEVEL = atoi(optarg);
+ break;
- if (!directory_exist(fname,NULL))
- mkdir(fname,0755);
+ case 'p':
+ port = atoi(optarg);
+ break;
- strcat(fname,"/");
- strcat(fname,name);
- strcat(fname,".LCK");
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(0);
+ break;
- if (!file_exist(fname,NULL))
- {
- f = fopen(fname,"w");
- if (f) fclose(f);
- }
-
- total_recs = file_size(fname) / sizeof(crec);
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
- f = fopen(fname,"r+");
+ reopen_logs();
- if (!f)
- {
- DEBUG(1,("couldn't open lock file %s\n",fname));
- return(False);
- }
+ DEBUG(1,( "smbd version %s started.\n", VERSION));
+ DEBUGADD(1,( "Copyright Andrew Tridgell 1992-1998\n"));
- /* find a free spot */
- for (i=0;i<max_connections;i++)
- {
+ DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
+ (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid()));
- 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;
- }
-
- 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;
+ 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 (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)
- {
- 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;
+ init_structs();
+
+ if (!reload_services(False))
+ return(-1);
- outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize);
- }
- else
+#ifdef WITH_SSL
{
- outsize = reply_unknown(inbuf,outbuf);
+ extern BOOL sslEnabled;
+ sslEnabled = lp_ssl_enabled();
+ if(sslEnabled)
+ sslutil_init(True);
}
- }
-
-#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
+#endif /* WITH_SSL */
- return(outsize);
-}
+ codepage_initialise(lp_client_code_page());
+ pstrcpy(global_myworkgroup, lp_workgroup());
-/****************************************************************************
-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
+ if(!pdb_generate_machine_sid()) {
+ DEBUG(0,("ERROR: Samba cannot get a machine SID.\n"));
+ exit(1);
+ }
-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;
+ CatchSignal(SIGHUP,SIGNAL_CAST sig_hup);
+
+ /* Setup the signals that allow the debug log level
+ to by dynamically changed. */
+ /* If we are using the malloc debug code we can't use
+ SIGUSR1 and SIGUSR2 to do debug level changes. */
+
+#ifndef MEM_MAN
+#if defined(SIGUSR1)
+ CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
+
+#if defined(SIGUSR2)
+ CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+#endif /* MEM_MAN */
- 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;
-
- /* 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);
-}
-
-
-/****************************************************************************
- 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();
+ DEBUG(3,( "loaded services\n"));
- {
- 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);
+ check_kernel_oplocks();
- DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+ if (!directory_exist(lp_lockdir(), NULL)) {
+ mkdir(lp_lockdir(), 0755);
+ }
- nread = len + 4;
-
- DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+ if (is_daemon) {
+ pidfile_create("smbd");
+ }
-#ifdef WITH_VTP
- if(trans_num == 1 && VT_Check(InBuffer)) {
- VT_Process();
- return;
- }
-#endif
+ if (!open_sockets(is_daemon,port))
+ exit(1);
+ if (!locking_init(0))
+ exit(1);
- if (msg_type == 0)
- show_msg(InBuffer);
+ if(!initialize_password_db())
+ exit(1);
- nread = construct_reply(InBuffer,OutBuffer,nread,maxxmit);
-
- if(nread > 0) {
- if (CVAL(OutBuffer,0) == 0)
- show_msg(OutBuffer);
+ /* possibly reload the services file. */
+ reload_services(True);
- 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++;
- }
-}
-
-
-/****************************************************************************
- 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();
-}
-
-/****************************************************************************
-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");
-}
-
-
-/****************************************************************************
- 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
-
-#ifdef SecureWare
- setluid(0);
-#endif
-
- append_log = True;
-
- TimeInit();
-
- strcpy(debugf,SMBLOGFILE);
-
- setup_logging(argv[0],False);
-
- charset_initialise();
-
- /* 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
-
- fault_setup(exit_server);
-
- umask(0777 & ~DEF_CREATE_MASK);
-
- initial_uid = geteuid();
- initial_gid = getegid();
-
- 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;
- }
- break;
- case 's':
- strcpy(servicesf,optarg);
- break;
- case 'l':
- strcpy(debugf,optarg);
- break;
- case 'a':
- {
- extern BOOL append_log;
- append_log = !append_log;
+ if (*lp_rootdir()) {
+ if (sys_chroot(lp_rootdir()) == 0)
+ DEBUG(2,("Changed root to %s\n", lp_rootdir()));
}
- 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()));
+ /* Setup the oplock IPC socket. */
+ if( !open_oplock_ipc() )
+ exit(1);
- 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()));
- }
-
- process();
- close_sockets();
- }
- exit_server("normal exit");
- return(0);
+ smbd_process();
+ close_sockets();
+
+ exit_server("normal exit");
+ return(0);
}
-
-
diff --git a/source/smbd/service.c b/source/smbd/service.c
new file mode 100644
index 00000000000..b0c74aa53e7
--- /dev/null
+++ b/source/smbd/service.c
@@ -0,0 +1,542 @@
+/*
+ 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 int DEBUGLEVEL;
+
+extern time_t 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 pstring sesssetup_user;
+extern fstring remote_machine;
+
+
+/****************************************************************************
+load parameters specific to a connection/service
+****************************************************************************/
+BOOL become_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;
+
+ snum = SNUM(conn);
+
+ if (do_chdir &&
+ ChDir(conn->connectpath) != 0 &&
+ ChDir(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);
+}
+
+
+/****************************************************************************
+ 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);
+
+ if(!phome_dir)
+ {
+ /*
+ * Try mapping the servicename, it may
+ * be a Windows to unix mapped user name.
+ */
+ if(map_username(service))
+ 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 *pdefservice = lp_defaultservice();
+ if (pdefservice && *pdefservice && !strequal(pdefservice,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)
+ {
+ 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);
+}
+
+
+/****************************************************************************
+ make a connection to a service
+****************************************************************************/
+connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
+{
+ int snum;
+ struct passwd *pass = NULL;
+ BOOL guest = False;
+ BOOL force = False;
+ extern int Client;
+ connection_struct *conn;
+
+ strlower(service);
+
+ snum = find_service(service);
+ if (snum < 0) {
+ extern int Client;
+ if (strequal(service,"IPC$")) {
+ DEBUG(3,("refusing IPC connection\n"));
+ *ecode = ERRnoipc;
+ return NULL;
+ }
+
+ DEBUG(0,("%s (%s) couldn't find service %s\n",
+ remote_machine, client_addr(Client), service));
+ *ecode = ERRinvnetname;
+ return NULL;
+ }
+
+ if (strequal(service,HOMES_NAME)) {
+ if (*user && Get_Pwnam(user,True))
+ return(make_connection(user,user,password,
+ pwlen,dev,vuid,ecode));
+
+ if(lp_security() != SEC_SHARE) {
+ if (validated_username(vuid)) {
+ pstrcpy(user,validated_username(vuid));
+ return(make_connection(user,user,password,pwlen,dev,vuid,ecode));
+ }
+ } else {
+ /* Security = share. Try with sesssetup_user
+ * as the username. */
+ if(*sesssetup_user) {
+ pstrcpy(user,sesssetup_user);
+ return(make_connection(user,user,password,pwlen,dev,vuid,ecode));
+ }
+ }
+ }
+
+ if (!lp_snum_ok(snum) ||
+ !check_access(Client,
+ lp_hostsallow(snum), lp_hostsdeny(snum))) {
+ *ecode = ERRaccess;
+ return NULL;
+ }
+
+ /* you can only connect to the IPC$ service as an ipc device */
+ if (strequal(service,"IPC$"))
+ 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"));
+ *ecode = ERRinvdevice;
+ return NULL;
+ }
+
+ /* 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, ( "Invalid username/password for %s\n", service ) );
+ *ecode = ERRbadpw;
+ return NULL;
+ }
+
+ conn = conn_new();
+ if (!conn) {
+ DEBUG(0,("Couldn't find free connection.\n"));
+ *ecode = ERRnoresource;
+ conn_free(conn);
+ return NULL;
+ }
+
+ /* find out some info about the user */
+ pass = Get_Pwnam(user,True);
+
+ if (pass == NULL) {
+ DEBUG(0,( "Couldn't find account %s\n",user));
+ *ecode = ERRbaduid;
+ conn_free(conn);
+ return NULL;
+ }
+
+ conn->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))
+ conn->read_only = True;
+
+ StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
+ string_sub(list,"%S",service);
+
+ if (user_in_list(user,list))
+ conn->read_only = False;
+ }
+
+ /* 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(user,lp_admin_users(snum))
+#if 0
+ && !conn->read_only
+#endif
+ ) {
+ conn->admin_user = True;
+ DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
+ } else {
+ conn->admin_user = False;
+ }
+
+ conn->force_user = force;
+ conn->vuid = vuid;
+ conn->uid = pass->pw_uid;
+ conn->gid = pass->pw_gid;
+ 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);
+ 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);
+
+#ifdef HAVE_GETGRNAM
+ if (*lp_force_group(snum)) {
+ struct group *gptr;
+ pstring gname;
+
+ StrnCpy(gname,lp_force_group(snum),sizeof(pstring)-1);
+ /* default service may be a group name */
+ string_sub(gname,"%S",service);
+ gptr = (struct group *)getgrnam(gname);
+
+ if (gptr) {
+ conn->gid = gptr->gr_gid;
+ DEBUG(3,("Forced group %s\n",gname));
+ } else {
+ DEBUG(1,("Couldn't find group %s\n",gname));
+ }
+ }
+#endif
+
+ if (*lp_force_user(snum)) {
+ struct passwd *pass2;
+ fstring fuser;
+ fstrcpy(fuser,lp_force_user(snum));
+ pass2 = (struct passwd *)Get_Pwnam(fuser,True);
+ if (pass2) {
+ conn->uid = pass2->pw_uid;
+ 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));
+ }
+ }
+
+ {
+ pstring s;
+ pstrcpy(s,lp_pathname(snum));
+ standard_sub(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;
+
+ if (!IS_IPC(conn)) {
+ /* Find all the groups this uid is in and
+ store them. Used by become_user() */
+ setup_groups(conn->user,conn->uid,conn->gid,
+ &conn->ngroups,&conn->groups);
+
+ /* 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"));
+ *ecode = ERRnoresource;
+ conn_free(conn);
+ return NULL;
+ }
+
+ if (lp_status(SNUM(conn)))
+ claim_connection(conn,"STATUS.",
+ MAXSTATUS,False);
+ } /* IS_IPC */
+
+ /* execute any "root preexec = " line */
+ if (*lp_rootpreexec(SNUM(conn))) {
+ pstring cmd;
+ pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
+ standard_sub(conn,cmd);
+ DEBUG(5,("cmd=%s\n",cmd));
+ smbrun(cmd,NULL,False);
+ }
+
+ if (!become_user(conn, conn->vuid)) {
+ DEBUG(0,("Can't become connected user!\n"));
+ if (!IS_IPC(conn)) {
+ yield_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)));
+ if (lp_status(SNUM(conn))) {
+ yield_connection(conn,"STATUS.",MAXSTATUS);
+ }
+ }
+ conn_free(conn);
+ *ecode = ERRbadpw;
+ return NULL;
+ }
+
+ if (ChDir(conn->connectpath) != 0) {
+ DEBUG(0,("Can't change directory to %s (%s)\n",
+ conn->connectpath,strerror(errno)));
+ unbecome_user();
+ if (!IS_IPC(conn)) {
+ yield_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)));
+ if (lp_status(SNUM(conn)))
+ yield_connection(conn,"STATUS.",MAXSTATUS);
+ }
+ conn_free(conn);
+ *ecode = ERRinvnetname;
+ return NULL;
+ }
+
+ string_set(&conn->origpath,conn->connectpath);
+
+#if SOFTLINK_OPTIMISATION
+ /* resolve any soft links early */
+ {
+ pstring s;
+ pstrcpy(s,conn->connectpath);
+ GetWd(s);
+ string_set(&conn->connectpath,s);
+ ChDir(conn->connectpath);
+ }
+#endif
+
+ add_session_user(user);
+
+ /* execute any "preexec = " line */
+ if (*lp_preexec(SNUM(conn))) {
+ pstring cmd;
+ pstrcpy(cmd,lp_preexec(SNUM(conn)));
+ standard_sub(conn,cmd);
+ smbrun(cmd,NULL,False);
+ }
+
+ /* we've finished with the sensitive stuff */
+ unbecome_user();
+
+ /* 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)));
+ }
+
+ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
+ extern int Client;
+
+ dbgtext( "%s (%s) ", remote_machine, client_addr(Client) );
+ dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
+ dbgtext( "as user %s ", user );
+ dbgtext( "(uid=%d, gid=%d) ", conn->uid, conn->gid );
+ dbgtext( "(pid %d)\n", (int)getpid() );
+ }
+
+ return(conn);
+}
+
+
+/****************************************************************************
+close a cnum
+****************************************************************************/
+void close_cnum(connection_struct *conn, uint16 vuid)
+{
+ extern int Client;
+ DirCacheFlush(SNUM(conn));
+
+ unbecome_user();
+
+ DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
+ remote_machine,client_addr(Client),
+ lp_servicename(SNUM(conn))));
+
+ yield_connection(conn,
+ lp_servicename(SNUM(conn)),
+ lp_max_connections(SNUM(conn)));
+
+ if (lp_status(SNUM(conn)))
+ yield_connection(conn,"STATUS.",MAXSTATUS);
+
+ file_close_conn(conn);
+ dptr_closecnum(conn);
+
+ /* execute any "postexec = " line */
+ if (*lp_postexec(SNUM(conn)) &&
+ become_user(conn, vuid)) {
+ pstring cmd;
+ pstrcpy(cmd,lp_postexec(SNUM(conn)));
+ standard_sub(conn,cmd);
+ smbrun(cmd,NULL,False);
+ unbecome_user();
+ }
+
+ unbecome_user();
+ /* execute any "root postexec = " line */
+ if (*lp_rootpostexec(SNUM(conn))) {
+ pstring cmd;
+ pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
+ standard_sub(conn,cmd);
+ smbrun(cmd,NULL,False);
+ }
+
+ conn_free(conn);
+}
+
+
diff --git a/source/smbd/ssl.c b/source/smbd/ssl.c
new file mode 100644
index 00000000000..27bb8f3a525
--- /dev/null
+++ b/source/smbd/ssl.c
@@ -0,0 +1,265 @@
+/*
+ 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.
+*/
+
+#ifdef WITH_SSL /* should always be defined if this module is compiled */
+
+#include "includes.h"
+#include <ssl.h>
+#include <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 export)
+{
+static RSA *rsa = NULL;
+
+ if(rsa == NULL)
+ rsa = RSA_generate_key(512, 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;
+char *certfile, *keyfile, *ciphers, *cacertDir, *cacertFile;
+
+ SSL_load_error_strings();
+ SSLeay_add_ssl_algorithms();
+ 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_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_privkey() : lp_ssl_client_privkey();
+ if(keyfile == NULL || *keyfile == 0)
+ keyfile = certfile;
+ if(certfile != NULL && *certfile != 0){
+ if(!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)){
+ 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();
+ 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, client_name(fd), client_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(fd) ) );
+ send_smb(fd, (char *)buf);
+ return -1;
+ }
+ buf[4] = 0x8e; /* negative session response: use SSL */
+ send_smb(fd, (char *)buf);
+ if(sslutil_accept(fd) != 0){
+ DEBUG( 0, ( "Client %s failed SSL negotiation!\n", client_addr(fd) ) );
+ return -1;
+ }
+ return 1;
+}
+
+#else /* WITH_SSL */
+ void ssl_dummy(void) {;} /* So some compilers don't complain. */
+#endif /* WITH_SSL */
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 9d02123cf87..6fd0272a0ab 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-1998
Extensively modified by Andrew Tridgell, 1995
@@ -22,15 +22,15 @@
*/
#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;
/****************************************************************************
Send the required number of replies back.
@@ -39,22 +39,23 @@ extern int Client;
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 = 3;
+ int data_alignment_offset = 0;
/* Initially set the wcnt area to be 10 - this is true for all
trans2 replies */
@@ -63,93 +64,113 @@ 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;
- }
+ {
+ send_smb(Client,outbuf);
+ 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);
- 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);
+ /* 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));
- 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);
+ 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);
- /* Calculate how many parameters and data we can fit into
- this packet. Parameters get precedence */
+ set_message(outbuf, 10, total_sent_thistime, True);
- 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);
+ /* Set total params and data to be sent */
+ SSVAL(outbuf,smb_tprcnt,paramsize);
+ SSVAL(outbuf,smb_tdrcnt,datasize);
- 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);
- }
+ /* Calculate how many parameters and data we can fit into
+ this packet. Parameters get precedence */
- 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_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);
+ 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);
+ }
+
+ 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);
+ }
- /* 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);
+ /* 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,("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));
+ 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);
+ /* Send the packet */
+ send_smb(Client,outbuf);
- pp += params_sent_thistime;
- pd += data_sent_thistime;
+ pp += params_sent_thistime;
+ pd += data_sent_thistime;
- params_to_send -= params_sent_thistime;
- data_to_send -= 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;
}
@@ -158,12 +179,14 @@ static int send_trans2_replies(char *outbuf, int bufsize, char *params,
/****************************************************************************
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);
@@ -175,49 +198,66 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
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);
- 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));
/* XXXX we need to handle passed times, sattr and flags */
- unix_convert(fname,cnum);
+ unix_convert(fname,conn,0,&bad_path,NULL);
- fnum = find_free_file();
- if (fnum < 0)
+ fsp = file_new();
+ if (!fsp)
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;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- unixmode = unix_mode(cnum,open_attr | aARCH);
-
+ unixmode = unix_mode(conn,open_attr | aARCH);
- open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
- &rmode,&smb_action);
+ open_file_shared(fsp,conn,fname,open_mode,open_ofun,unixmode,
+ oplock_request, &rmode,&smb_action);
- if (!Files[fnum].open)
+ if (!fsp->open)
+ {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ file_free(fsp);
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- close_file(fnum);
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ close_file(fsp,False);
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);
+ close_file(fsp,False);
return(ERROR(ERRDOS,ERRnoaccess));
}
@@ -227,13 +267,20 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
return(ERROR(ERRDOS,ERRnomem));
bzero(params,28);
- SSVAL(params,0,fnum);
+ 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 */
@@ -245,7 +292,8 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
/****************************************************************************
get a level dependent lanman2 dir entry.
****************************************************************************/
-static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_level,
+static int get_lanman2_dir_entry(connection_struct *conn,
+ char *path_mask,int dirtype,int info_level,
int requires_resume_key,
BOOL dont_descend,char **ppdata,
char *base_data, int space_remaining,
@@ -254,140 +302,146 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
{
char *dname;
BOOL found = False;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
pstring mask;
pstring pathreal;
pstring fname;
- BOOL matched;
char *p, *pdata = *ppdata;
- int reskey=0, prev_dirpos=0;
+ uint32 reskey=0;
+ int 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,"/"));
+ SMB_OFF_T size = 0;
+ uint32 len;
+ time_t mdate=0, adate=0, cdate=0;
+ char *nameptr;
+ BOOL isrootdir = (strequal(conn->dirpath,"./") ||
+ strequal(conn->dirpath,".") ||
+ strequal(conn->dirpath,"/"));
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;
- if (!Connections[cnum].dirptr)
+ if (!conn->dirptr)
return(False);
p = strrchr(path_mask,'/');
if(p != NULL)
- {
- if(p[1] == '\0')
- strcpy(mask,"*.*");
- else
- strcpy(mask, p+1);
- }
+ {
+ if(p[1] == '\0')
+ pstrcpy(mask,"*.*");
+ else
+ pstrcpy(mask, p+1);
+ }
else
- strcpy(mask, path_mask);
+ pstrcpy(mask, path_mask);
while (!found)
- {
- /* Needed if we run out of space */
- prev_dirpos = TellDir(Connections[cnum].dirptr);
- dname = ReadDirName(Connections[cnum].dirptr);
+ {
+ /* Needed if we run out of space */
+ prev_dirpos = TellDir(conn->dirptr);
+ dname = ReadDirName(conn->dirptr);
- reskey = TellDir(Connections[cnum].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.
+ */
- DEBUG(6,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
- Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
-
- if (!dname)
- return(False);
+ reskey = 0;
- matched = False;
+ DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
+ (unsigned)conn->dirptr,TellDir(conn->dirptr)));
+
+ if (!dname)
+ return(False);
- strcpy(fname,dname);
+ pstrcpy(fname,dname);
- if(mask_match(fname, mask, case_sensitive, True))
- {
- BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
- if (dont_descend && !isdots)
- continue;
+ if(mask_match(fname, mask, case_sensitive, True))
+ {
+ 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));
+ if (isrootdir && isdots)
+ continue;
+
+ pstrcpy(pathreal,conn->dirpath);
+ if(needslash)
+ pstrcat(pathreal,"/");
+ pstrcat(pathreal,dname);
+ if (dos_stat(pathreal,&sbuf) != 0)
+ {
+ DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
+ continue;
+ }
+
+ 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;
+ mdate = sbuf.st_mtime;
+ adate = sbuf.st_atime;
+ cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ 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
+ name_map_mangle(fname,False,SNUM(conn));
p = pdata;
- name_ptr = p;
+ nameptr = p;
- name_map_mangle(fname,False,SNUM(cnum));
+ nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
switch (info_level)
- {
+ {
case 1:
if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
+ 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_cbFile,(uint32)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;
+ pstrcpy(p + l1_achName, fname);
+ nameptr = 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;
+ 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_cbFile,(uint32)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;
+ pstrcpy(p + l2_achName, fname);
+ nameptr = p + l2_achName;
p += l2_achName + strlen(fname) + 1;
break;
@@ -396,36 +450,36 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
put_dos_date2(p,4,cdate);
put_dos_date2(p,8,adate);
put_dos_date2(p,12,mdate);
- SIVAL(p,16,size);
+ SIVAL(p,16,(uint32)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;
+ pstrcpy(p+31, fname);
+ nameptr = p+31;
p += 31 + strlen(fname) + 1;
break;
case 4:
if(requires_resume_key) {
- SIVAL(p,0,reskey);
- p += 4;
+ 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,16,(uint32)size);
SIVAL(p,20,ROUNDUP(size,1024));
SSVAL(p,24,mode);
CVAL(p,32) = strlen(fname);
- strcpy(p + 33, fname);
- name_ptr = p+33;
+ pstrcpy(p + 33, fname);
+ nameptr = p+33;
p += 33 + strlen(fname) + 1;
break;
case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
- was_8_3 = is_8_3(fname);
+ was_8_3 = is_8_3(fname, True);
len = 94+strlen(fname);
len = (len + 3) & ~3;
SIVAL(p,0,len); p += 4;
@@ -434,26 +488,23 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
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;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); 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;
+ pstrcpy(p+2,fname);
+ if (!name_map_mangle(p+2,True,SNUM(conn)))
+ (p+2)[12] = 0;
} else
- *(p+2) = 0;
+ *(p+2) = 0;
strupper(p+2);
SSVAL(p,0,strlen(p+2));
p += 2 + 24;
- /* name_ptr = p; */
- strcpy(p,fname); p += strlen(p);
+ /* nameptr = p; */
+ pstrcpy(p,fname); p += strlen(p);
p = pdata + len;
break;
@@ -466,11 +517,12 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
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;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
SIVAL(p,0,strlen(fname)); p += 4;
- strcpy(p,fname);
+ pstrcpy(p,fname);
p = pdata + len;
break;
@@ -484,12 +536,13 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
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;
+ SOFF_T(p,0,size);
+ SOFF_T(p,8,size);
+ p += 16;
+ SIVAL(p,0,nt_extmode); p += 4;
SIVAL(p,0,strlen(fname)); p += 4;
SIVAL(p,0,0); p += 4;
- strcpy(p,fname);
+ pstrcpy(p,fname);
p = pdata + len;
break;
@@ -499,7 +552,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
SIVAL(p,0,len); p += 4;
SIVAL(p,0,reskey); p += 4;
SIVAL(p,0,strlen(fname)); p += 4;
- strcpy(p,fname);
+ pstrcpy(p,fname);
p = pdata + len;
break;
@@ -510,24 +563,52 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
if (PTR_DIFF(p,pdata) > space_remaining) {
/* Move the dirptr back to prev_dirpos */
- SeekDir(Connections[cnum].dirptr, 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 */
}
/* Setup the last_filename pointer, as an offset from base_data */
- *last_name_off = PTR_DIFF(name_ptr,base_data);
+ *last_name_off = PTR_DIFF(nameptr,base_data);
/* Advance the data pointer to the next slot */
*ppdata = p;
return(found);
}
/****************************************************************************
+ Convert the directory masks formated for the wire.
+****************************************************************************/
+
+void mask_convert( char *mask)
+{
+ /*
+ * We know mask is a pstring.
+ */
+ char *p = mask;
+ while (*p) {
+ if (*p == '<') {
+ pstring expnd;
+ if(p[1] != '"' && p[1] != '.') {
+ pstrcpy( expnd, p+1 );
+ *p++ = '*';
+ *p = '.';
+ safe_strcpy( p+1, expnd, sizeof(pstring) - (p - mask) - 2);
+ } else
+ *p = '*';
+ }
+ if (*p == '>') *p = '?';
+ if (*p == '"') *p = '.';
+ p++;
+ }
+}
+
+/****************************************************************************
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 +635,7 @@ 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;
*directory = *mask = 0;
@@ -576,22 +658,38 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
return(ERROR(ERRDOS,ERRunknownlevel));
}
- strcpy(directory, params + 12); /* Complete directory path with
+ pstrcpy(directory, params + 12); /* Complete directory path with
wildcard mask appended */
DEBUG(5,("path=%s\n",directory));
- unix_convert(directory,cnum);
- if(!check_name(directory,cnum)) {
+ unix_convert(directory,conn,0,&bad_path,NULL);
+ if(!check_name(directory,conn)) {
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+
+#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
+
return(ERROR(ERRDOS,ERRbadpath));
}
p = strrchr(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;
}
@@ -607,27 +705,27 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
- dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
+ dptr_num = dptr_create(conn,directory, True ,SVAL(inbuf,smb_pid));
if (dptr_num < 0)
- return(ERROR(ERRDOS,ERRbadpath));
+ return(ERROR(ERRDOS,ERRbadfile));
+
+ /* Convert the formatted mask. */
+ mask_convert(mask);
+
+#if 0 /* JRA */
+ /*
+ * Now we have a working mask_match in util.c, I believe
+ * we no longer need these hacks (in fact they break
+ * things). JRA.
+ */
- /* convert the formatted masks */
- {
- p = mask;
- while (*p) {
- if (*p == '<') *p = '*';
- if (*p == '>') *p = '?';
- if (*p == '"') *p = '.';
- p++;
- }
- }
-
/* a special case for 16 bit apps */
- if (strequal(mask,"????????.???")) strcpy(mask,"*");
+ if (strequal(mask,"????????.???")) pstrcpy(mask,"*");
/* handle broken clients that send us old 8.3 format */
string_sub(mask,"????????","*");
string_sub(mask,".???",".*");
+#endif /* JRA */
/* Save the wildcard match and attribs we are using on this directory -
needed as lanman2 assumes these are being saved between calls */
@@ -646,8 +744,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;
@@ -667,7 +765,7 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
else
{
finished =
- !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
+ !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
requires_resume_key,dont_descend,
&p,pdata,space_remaining, &out_of_space,
&last_name_off);
@@ -689,6 +787,14 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
dptr_num = -1;
}
+ /*
+ * If there are no matching entries we must return ERRDOS/ERRbadfile -
+ * from observation of NT.
+ */
+
+ if(numentries == 0)
+ return(ERROR(ERRDOS,ERRbadfile));
+
/* At this point pdata points to numentries directory entries. */
/* Set up the return parameter block */
@@ -701,12 +807,11 @@ 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 %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( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries ) );
return(-1);
}
@@ -715,8 +820,10 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
/****************************************************************************
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
@@ -734,6 +841,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 +853,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;
+
+ pstrcpy( resume_name, params+12);
- 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",
+ 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)
{
@@ -777,41 +889,114 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
return(ERROR(ERRDOS,ERRnomem));
/* Check that the dptr is valid */
- if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
+ if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num)))
return(ERROR(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));
}
- 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",
dptr_num, mask, dirtype,
- Connections[cnum].dirptr,
- TellDir(Connections[cnum].dirptr)));
+ (unsigned)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);
+
+ /*
+ * 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, 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)
+ {
+ 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, 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 */
for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
{
@@ -825,7 +1010,7 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
else
{
finished =
- !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
+ !get_lanman2_dir_entry(conn,mask,dirtype,info_level,
requires_resume_key,dont_descend,
&p,pdata,space_remaining, &out_of_space,
&last_name_off);
@@ -857,12 +1042,11 @@ 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);
}
@@ -870,19 +1054,25 @@ static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsiz
/****************************************************************************
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)
{
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));
+ SMB_STRUCT_STAT st;
+ char *vname = volume_label(SNUM(conn));
+ int snum = SNUM(conn);
+ char *fstype = lp_fstype(SNUM(conn));
+ extern uint32 global_client_caps;
+
+ DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
- if(sys_stat(".",&st)!=0) {
+ if(dos_stat(".",&st)!=0) {
DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
return (ERROR(ERRSRV,ERRinvdevice));
}
@@ -890,61 +1080,91 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,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;
+ {
+ SMB_BIG_UINT 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=%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 */
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);
+ /*
+ * 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) );
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,
+ DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
+ (unsigned)st.st_ctime, volname_len,
pdata+l2_vol_szVolLabel));
break;
}
case SMB_QUERY_FS_ATTRIBUTE_INFO:
- data_len = 12 + 2*strlen(FSTYPE_STRING);
+ data_len = 12 + 2*strlen(fstype);
+ SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES); /* FS ATTRIBUTES */
+#if 0 /* Old code. JRA. */
SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
+#endif /* Old code. */
SIVAL(pdata,4,128); /* Max filename component length */
- SIVAL(pdata,8,2*strlen(FSTYPE_STRING));
- PutUniCode(pdata+12,FSTYPE_STRING);
+ SIVAL(pdata,8,2*strlen(fstype));
+ PutUniCode(pdata+12,fstype);
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2)|FLAGS2_UNICODE_STRINGS);
break;
case SMB_QUERY_FS_LABEL_INFO:
data_len = 4 + strlen(vname);
SIVAL(pdata,0,strlen(vname));
- strcpy(pdata+4,vname);
+ pstrcpy(pdata+4,vname);
break;
case SMB_QUERY_FS_VOLUME_INFO:
- data_len = 17 + strlen(vname);
- SIVAL(pdata,12,strlen(vname));
- strcpy(pdata+17,vname);
+
+ /*
+ * 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));
+
+ /* NT4 always serves this up as unicode but expects it to be
+ * delivered as ascii! (tridge && JRA)
+ */
+ if (global_client_caps & CAP_NT_SMBS) {
+ data_len = 18 + strlen(vname);
+ SIVAL(pdata,12,strlen(vname));
+ pstrcpy(pdata+18,vname);
+ } else {
+ data_len = 18 + 2*strlen(vname);
+ SIVAL(pdata,12,strlen(vname)*2);
+ PutUniCode(pdata+18,vname);
+ }
+
+ DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n",
+ strlen(vname),vname));
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;
+ sys_disk_free(".",&bsize,&dfree,&dsize);
+ SIVAL(pdata,0,dsize);
+ SIVAL(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 */
@@ -952,12 +1172,13 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
break;
default:
return(ERROR(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;
}
@@ -965,15 +1186,17 @@ static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize
/****************************************************************************
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))
+ if (!CAN_WRITE(conn))
return(ERROR(ERRSRV,ERRaccess));
outsize = set_message(outbuf,10,0,True);
@@ -982,10 +1205,13 @@ 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)
{
@@ -994,36 +1220,42 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
uint16 tran_call = SVAL(inbuf, smb_setup0);
uint16 info_level;
int mode=0;
- int size=0;
+ SMB_OFF_T size=0;
unsigned int data_size;
- struct stat sbuf;
+ SMB_STRUCT_STAT sbuf;
pstring fname1;
char *fname;
char *p;
- int l,pos;
-
+ int l;
+ SMB_OFF_T pos;
+ BOOL bad_path = False;
if (tran_call == TRANSACT2_QFILEINFO) {
- int16 fnum = SVAL(params,0);
+ files_struct *fsp = file_fsp(params,0);
info_level = SVAL(params,2);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
- fname = Files[fnum].name;
- if (fstat(Files[fnum].fd,&sbuf) != 0) {
- DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
+ fname = fsp->fsp_name;
+ if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+ DEBUG(3,("fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
return(UNIXERROR(ERRDOS,ERRbadfid));
}
- pos = lseek(Files[fnum].fd,0,SEEK_CUR);
+ pos = sys_lseek(fsp->fd_ptr->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)) {
+ pstrcpy(fname,&params[6]);
+ unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (!check_name(fname,conn) || (!VALID_STAT(sbuf) && dos_stat(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));
}
pos = 0;
@@ -1039,9 +1271,12 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
else
p++;
l = strlen(p);
- mode = dos_mode(cnum,fname,&sbuf);
+ mode = dos_mode(conn,fname,&sbuf);
size = sbuf.st_size;
if (mode & aDIR) size = 0;
+
+ /* from now on we only want the part after the / */
+ fname = p;
params = *pparams = Realloc(*pparams,2); bzero(params,2);
data_size = 1024;
@@ -1050,42 +1285,36 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
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));
-#endif
}
bzero(pdata,data_size);
switch (info_level)
{
- case 1:
- case 2:
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
data_size = (info_level==1?22:26);
- put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime);
+ put_dos_date2(pdata,l1_fdateCreation,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
- put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime);
- SIVAL(pdata,l1_cbFile,size);
+ put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
+ SIVAL(pdata,l1_cbFile,(uint32)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;
- case 3:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
data_size = 24;
- put_dos_date2(pdata,0,sbuf.st_ctime);
+ put_dos_date2(pdata,0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
put_dos_date2(pdata,4,sbuf.st_atime);
put_dos_date2(pdata,8,sbuf.st_mtime);
- SIVAL(pdata,12,size);
+ SIVAL(pdata,12,(uint32)size);
SIVAL(pdata,16,ROUNDUP(size,1024));
SIVAL(pdata,20,mode);
break;
- case 4:
+ case SMB_INFO_QUERY_ALL_EAS:
data_size = 4;
SIVAL(pdata,0,data_size);
break;
@@ -1094,18 +1323,29 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */
case SMB_QUERY_FILE_BASIC_INFO:
- data_size = 36;
- put_long_date(pdata,sbuf.st_ctime);
+ data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
+ put_long_date(pdata,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
put_long_date(pdata+8,sbuf.st_atime);
- put_long_date(pdata+16,sbuf.st_mtime);
- put_long_date(pdata+24,sbuf.st_mtime);
+ 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 = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ 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_QUERY_FILE_STANDARD_INFO:
data_size = 22;
- SIVAL(pdata,0,size);
- SIVAL(pdata,8,size);
+ SOFF_T(pdata,0,size);
+ SOFF_T(pdata,8,size);
SIVAL(pdata,16,sbuf.st_nlink);
CVAL(pdata,20) = 0;
CVAL(pdata,21) = (mode&aDIR)?1:0;
@@ -1115,27 +1355,46 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
data_size = 4;
break;
- case SMB_QUERY_FILE_NAME_INFO:
+ /* Get the 8.3 name - used if NT SMB was negotiated. */
case SMB_QUERY_FILE_ALT_NAME_INFO:
+ {
+ pstring short_name;
+ pstrcpy(short_name,p);
+ /* Mangle if not already 8.3 */
+ if(!is_8_3(short_name, True))
+ {
+ if(!name_map_mangle(short_name,True,SNUM(conn)))
+ *short_name = '\0';
+ }
+ strupper(short_name);
+ l = strlen(short_name);
+ PutUniCode(pdata + 4, short_name);
+ data_size = 4 + (2*l);
+ SIVAL(pdata,0,2*l);
+ }
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
data_size = 4 + l;
SIVAL(pdata,0,l);
- strcpy(pdata+4,fname);
+ pstrcpy(pdata+4,fname);
break;
+
case SMB_QUERY_FILE_ALLOCATION_INFO:
case SMB_QUERY_FILE_END_OF_FILEINFO:
data_size = 8;
- SIVAL(pdata,0,size);
+ SOFF_T(pdata,0,size);
break;
case SMB_QUERY_FILE_ALL_INFO:
- put_long_date(pdata,sbuf.st_ctime);
+ put_long_date(pdata,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
put_long_date(pdata+8,sbuf.st_atime);
- put_long_date(pdata+16,sbuf.st_mtime);
- put_long_date(pdata+24,sbuf.st_mtime);
+ 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;
- SIVAL(pdata,0,size);
- SIVAL(pdata,8,size);
+ SOFF_T(pdata,0,size);
+ SOFF_T(pdata,8,size);
SIVAL(pdata,16,sbuf.st_nlink);
CVAL(pdata,20) = 0;
CVAL(pdata,21) = (mode&aDIR)?1:0;
@@ -1143,9 +1402,9 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
pdata += 8; /* index number */
pdata += 4; /* EA info */
if (mode & aRONLY)
- SIVAL(pdata,0,0xA9);
+ SIVAL(pdata,0,0xA9);
else
- SIVAL(pdata,0,0xd01BF);
+ SIVAL(pdata,0,0xd01BF);
pdata += 4;
SIVAL(pdata,0,pos); /* current offset */
pdata += 8;
@@ -1153,19 +1412,24 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
pdata += 4;
pdata += 4; /* alignment */
SIVAL(pdata,0,l);
- strcpy(pdata+4,fname);
+ pstrcpy(pdata+4,fname);
pdata += 4 + l;
data_size = PTR_DIFF(pdata,(*ppdata));
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:
data_size = 24 + l;
SIVAL(pdata,0,pos);
SIVAL(pdata,4,size);
SIVAL(pdata,12,size);
SIVAL(pdata,20,l);
- strcpy(pdata+24,fname);
+ pstrcpy(pdata+24,fname);
break;
+#endif
+
default:
return(ERROR(ERRDOS,ERRunknownlevel));
}
@@ -1178,8 +1442,9 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
/****************************************************************************
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;
@@ -1187,27 +1452,28 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
uint16 tran_call = SVAL(inbuf, smb_setup0);
uint16 info_level;
int mode=0;
- int size=0;
+ SMB_OFF_T size=0;
struct utimbuf tvs;
- struct stat st;
+ SMB_STRUCT_STAT st;
pstring fname1;
char *fname;
int fd = -1;
+ BOOL bad_path = False;
- if (!CAN_WRITE(cnum))
+ if (!CAN_WRITE(conn))
return(ERROR(ERRSRV,ERRaccess));
if (tran_call == TRANSACT2_SETFILEINFO) {
- int16 fnum = SVAL(params,0);
+ files_struct *fsp = file_fsp(params,0);
info_level = SVAL(params,2);
- CHECK_FNUM(fnum,cnum);
- CHECK_ERROR(fnum);
+ CHECK_FSP(fsp,conn);
+ CHECK_ERROR(fsp);
- fname = Files[fnum].name;
- fd = Files[fnum].fd;
+ fname = fsp->fsp_name;
+ fd = fsp->fd_ptr->fd;
- if(fstat(fd,&st)!=0) {
+ if(sys_fstat(fd,&st)!=0) {
DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
return(ERROR(ERRDOS,ERRbadpath));
}
@@ -1215,14 +1481,26 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
/* 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) {
+ pstrcpy(fname,&params[6]);
+ unix_convert(fname,conn,0,&bad_path,&st);
+ 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(st) && dos_stat(fname,&st)!=0) {
DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
- return(ERROR(ERRDOS,ERRbadpath));
+ if((errno == ENOENT) && bad_path)
+ {
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
+ }
+ return(UNIXERROR(ERRDOS,ERRbadpath));
}
}
@@ -1237,42 +1515,42 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
size = st.st_size;
tvs.modtime = st.st_mtime;
tvs.actime = st.st_atime;
- mode = dos_mode(cnum,fname,&st);
+ mode = dos_mode(conn,fname,&st);
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);
-
- send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
-
- return(-1);
+ return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
}
switch (info_level)
+ {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
{
- case 1:
+ /* access time */
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;
- case 2:
- 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;
+ }
- case 3:
+ /* 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;
- case 4:
+ /* 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);
@@ -1280,48 +1558,112 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
break;
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);
+ {
+ /* Ignore create time at offset pdata. */
+
+ /* access time */
+ tvs.actime = interpret_long_date(pdata+8);
+
+ /* write time + changed time, combined. */
+ tvs.modtime=MAX(interpret_long_date(pdata+16),
+ interpret_long_date(pdata+24));
+
+#if 0 /* Needs more testing... */
+ /* Test from Luke to prevent Win95 from
+ setting incorrect values here.
+ */
+ if (tvs.actime < tvs.modtime)
+ return(ERROR(ERRDOS,ERRnoaccess));
+#endif /* Needs more testing... */
+
+ /* attributes */
+ mode = IVAL(pdata,32);
break;
+ }
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);
+#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(ERRDOS,ERRunknownlevel));
+#endif /* LARGE_SMB_OFF_T */
+ break;
+ }
+
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ break; /* We don't need to do anything for this call. */
+
+ case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
+ {
+ if (tran_call == TRANSACT2_SETFILEINFO) {
+ files_struct *fsp = file_fsp(params,0);
+ if(fsp->is_directory)
+ return(ERROR(ERRDOS,ERRnoaccess));
+ /*
+ * TODO - check here is this means set
+ * this flag bit on all open files that
+ * reference this particular dev/inode pair.
+ * If so we'll need to search the open
+ * file entries here and set this flag on
+ * all of them that match. JRA.
+ */
+ fsp->delete_on_close = CVAL(pdata,0);
+ } else
+ return(ERROR(ERRDOS,ERRunknownlevel));
break;
+ }
- case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
- case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
default:
+ {
return(ERROR(ERRDOS,ERRunknownlevel));
}
+ }
+ 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));
+ /* get some defaults (no modifications) if any info is zero. */
if (!tvs.actime) tvs.actime = st.st_atime;
if (!tvs.modtime) tvs.modtime = st.st_mtime;
if (!size) size = st.st_size;
- /* 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)
+ /* 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(file_utime(conn, fname, &tvs)!=0)
+ {
return(ERROR(ERRDOS,ERRnoaccess));
+ }
}
- if(mode != dos_mode(cnum,fname,&st) && dos_chmod(cnum,fname,mode,NULL)) {
+
+ /* check the mode isn't different, before changing it */
+ if (mode != dos_mode(conn, fname, &st) && file_chmod(conn, 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(size != st.st_size)
+ {
+ if (fd == -1)
+ {
+ fd = dos_open(fname,O_RDWR,0);
if (fd == -1)
- return(ERROR(ERRDOS,ERRbadpath));
+ {
+ return(ERROR(ERRDOS,ERRbadpath));
+ }
set_filelen(fd, size);
close(fd);
- } else {
+ }
+ else
+ {
set_filelen(fd, size);
}
}
@@ -1336,27 +1678,34 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
/****************************************************************************
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;
+ BOOL bad_path = False;
- if (!CAN_WRITE(cnum))
+ if (!CAN_WRITE(conn))
return(ERROR(ERRSRV,ERRaccess));
- strcpy(directory, &params[4]);
+ pstrcpy(directory, &params[4]);
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,NULL);
+ if (check_name(directory,conn))
+ ret = dos_mkdir(directory,unix_mode(conn,aDIR));
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));
}
@@ -1376,8 +1725,10 @@ 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.
****************************************************************************/
-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;
@@ -1417,8 +1768,10 @@ 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.
****************************************************************************/
-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;
@@ -1440,207 +1793,258 @@ static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int
/****************************************************************************
reply to a SMBfindclose (stop trans2 directory search)
****************************************************************************/
-int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_findclose(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
{
- int cnum;
- int outsize = 0;
- uint16 dptr_num=SVAL(inbuf,smb_vwv0);
-
- cnum = SVAL(inbuf,smb_tid);
+ int outsize = 0;
+ int16 dptr_num=SVALS(inbuf,smb_vwv0);
- DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
+ DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
- dptr_close(dptr_num);
+ dptr_close(dptr_num);
- outsize = set_message(outbuf,0,0,True);
+ outsize = set_message(outbuf,0,0,True);
- DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
+ DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
- return(outsize);
+ return(outsize);
}
/****************************************************************************
reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
****************************************************************************/
-int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
+int reply_findnclose(connection_struct *conn,
+ char *inbuf,char *outbuf,int length,int bufsize)
{
- int cnum;
- int outsize = 0;
- int dptr_num= -1;
+ int outsize = 0;
+ int dptr_num= -1;
+
+ dptr_num = SVAL(inbuf,smb_vwv0);
- cnum = SVAL(inbuf,smb_tid);
- dptr_num = SVAL(inbuf,smb_vwv0);
+ DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
- DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
+ /* We never give out valid handles for a
+ findnotifyfirst - so any dptr_num is ok here.
+ Just ignore it. */
- /* 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);
- outsize = set_message(outbuf,0,0,True);
+ DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
- DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
-
- return(outsize);
+ return(outsize);
}
/****************************************************************************
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);
+ DEBUG(4,("Ignoring transs2 of length %d\n",length));
+ return(-1);
}
/****************************************************************************
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;
+ 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);
+ if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) {
+ /* Queue this open message as we are the process of an
+ * oplock break. */
- /* 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));
- }
+ DEBUG(2,("reply_trans2: queueing message trans2open due to being "));
+ DEBUGADD(2,( "in oplock break state.\n"));
+
+ push_oplock_pending_smb_message(inbuf, length);
+ return -1;
+ }
+
+ 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) {
+ DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
+ return(ERROR(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(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);
+ if ((total_params && !params) || (total_data && !data)) {
+ DEBUG(2,("Out of memory in reply_trans2\n"));
+ if(params)
+ free(params);
+ if(data)
+ free(data);
+ return(ERROR(ERRDOS,ERRnomem));
+ }
- 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);
+ send_smb(Client,outbuf);
+
+ 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" ));
+ if(params)
+ free(params);
+ if(data)
+ free(data);
+ return(ERROR(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) {
+ uint16 flg2 = SVAL(outbuf,smb_flg2);
+ SSVAL(outbuf,smb_flg2,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:
+ outsize = call_trans2open(conn,
+ inbuf, outbuf, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_FINDFIRST:
+ outsize = call_trans2findfirst(conn, inbuf, outbuf,
+ bufsize, &params, &data);
+ break;
+
+ case TRANSACT2_FINDNEXT:
+ outsize = call_trans2findnext(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_QFSINFO:
+ outsize = call_trans2qfsinfo(conn, inbuf, outbuf,
+ length, bufsize, &params,
+ &data);
+ break;
+
+ case TRANSACT2_SETFSINFO:
+ outsize = call_trans2setfsinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_QPATHINFO:
+ case TRANSACT2_QFILEINFO:
+ outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data, total_data);
+ break;
+ case TRANSACT2_SETPATHINFO:
+ case TRANSACT2_SETFILEINFO:
+ outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data,
+ total_data);
+ break;
+
+ case TRANSACT2_FINDNOTIFYFIRST:
+ outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+
+ case TRANSACT2_FINDNOTIFYNEXT:
+ outsize = call_trans2findnotifynext(conn, inbuf, outbuf,
+ length, bufsize,
+ &params, &data);
+ break;
+ case TRANSACT2_MKDIR:
+ outsize = call_trans2mkdir(conn, inbuf, outbuf, length,
+ bufsize, &params, &data);
+ break;
+ default:
+ /* Error in request */
+ DEBUG(2,("Unknown request %d in trans2 call\n", 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 */
}
diff --git a/source/smbd/uid.c b/source/smbd/uid.c
new file mode 100644
index 00000000000..4ffec90521c
--- /dev/null
+++ b/source/smbd/uid.c
@@ -0,0 +1,423 @@
+/*
+ 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"
+
+extern int DEBUGLEVEL;
+
+static int initial_uid;
+static int initial_gid;
+
+/* what user is current? */
+extern struct current_user current_user;
+
+pstring OriginalDir;
+
+/****************************************************************************
+initialise the uid routines
+****************************************************************************/
+void init_uid(void)
+{
+ initial_uid = current_user.uid = geteuid();
+ initial_gid = current_user.gid = getegid();
+
+ if (initial_gid != 0 && initial_uid == 0) {
+#ifdef HAVE_SETRESUID
+ setresgid(0,0,0);
+#else
+ setgid(0);
+ setegid(0);
+#endif
+ }
+
+ initial_uid = geteuid();
+ initial_gid = getegid();
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+
+ ChDir(OriginalDir);
+}
+
+
+/****************************************************************************
+ become the specified uid
+****************************************************************************/
+static BOOL become_uid(int uid)
+{
+ if (initial_uid != 0) {
+ return(True);
+ }
+
+ if (uid == -1 || uid == 65535) {
+ static int done;
+ if (!done) {
+ DEBUG(1,("WARNING: using uid %d is a security risk\n",
+ uid));
+ done=1;
+ }
+ }
+
+#ifdef HAVE_TRAPDOOR_UID
+#ifdef HAVE_SETUIDX
+ /* AIX3 has setuidx which is NOT a trapoor function (tridge) */
+ if (setuidx(ID_EFFECTIVE, (uid_t)uid) != 0) {
+ if (seteuid((uid_t)uid) != 0) {
+ DEBUG(1,("Can't set uid (setuidx)\n"));
+ return False;
+ }
+ }
+#endif
+#endif
+
+#ifdef HAVE_SETRESUID
+ 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,(int)getuid(), (int)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);
+ }
+
+ current_user.uid = uid;
+
+ return(True);
+}
+
+
+/****************************************************************************
+ become the specified gid
+****************************************************************************/
+static BOOL become_gid(int gid)
+{
+ if (initial_uid != 0)
+ return(True);
+
+ if (gid == -1 || gid == 65535) {
+ DEBUG(1,("WARNING: using gid %d is a security risk\n",gid));
+ }
+
+#ifdef HAVE_SETRESUID
+ 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,(int)getgid(),(int)getegid()));
+ if (gid > 32000) {
+ DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
+ }
+ return(False);
+ }
+
+ current_user.gid = gid;
+
+ 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
+****************************************************************************/
+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);
+
+#ifdef AIX
+ /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before setting IDs */
+ initgroups(pass->pw_name, (gid_t)pass->pw_gid);
+#endif
+
+ ret = become_id(pass->pw_uid,pass->pw_gid);
+
+ if (!ret) {
+ DEBUG(1,("Failed to become guest. Invalid guest account?\n"));
+ }
+
+ current_user.conn = NULL;
+ current_user.vuid = UID_FIELD_INVALID;
+
+ return(ret);
+}
+
+/*******************************************************************
+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->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
+****************************************************************************/
+BOOL become_user(connection_struct *conn, uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ int snum,gid;
+ int uid;
+
+ /*
+ * 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,("Skipping become_user - already user\n"));
+ return(True);
+ } else if ((current_user.conn == conn) &&
+ (vuser != 0) && (current_user.vuid == vuid) &&
+ (current_user.uid == vuser->uid)) {
+ DEBUG(4,("Skipping become_user - already user\n"));
+ return(True);
+ }
+
+ unbecome_user();
+
+ if (!conn) {
+ DEBUG(2,("Connection not open\n"));
+ return(False);
+ }
+
+ snum = SNUM(conn);
+
+ if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
+ return False;
+
+ if (conn->force_user ||
+ lp_security() == SEC_SHARE ||
+ !(vuser) || (vuser->guest)) {
+ uid = conn->uid;
+ gid = conn->gid;
+ current_user.groups = conn->groups;
+ current_user.ngroups = conn->ngroups;
+ } else {
+ if (!vuser) {
+ DEBUG(2,("Invalid vuid used %d\n",vuid));
+ return(False);
+ }
+ uid = vuser->uid;
+ if(!*lp_force_group(snum)) {
+ gid = vuser->gid;
+ } else {
+ gid = conn->gid;
+ }
+ current_user.ngroups = vuser->n_groups;
+ current_user.groups = vuser->groups;
+ }
+
+ if (initial_uid == 0) {
+ if (!become_gid(gid)) return(False);
+
+#ifdef HAVE_SETGROUPS
+ if (!(conn && conn->ipc)) {
+ /* groups stuff added by ih/wreu */
+ if (current_user.ngroups > 0)
+ if (setgroups(current_user.ngroups,
+ current_user.groups)<0) {
+ DEBUG(0,("setgroups call failed!\n"));
+ }
+ }
+#endif
+
+ if (!conn->admin_user && !become_uid(uid))
+ return(False);
+ }
+
+ current_user.conn = conn;
+ current_user.vuid = vuid;
+
+ DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d)\n",
+ (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
+
+ return(True);
+}
+
+/****************************************************************************
+ unbecome the user of a connection number
+****************************************************************************/
+BOOL unbecome_user(void )
+{
+ if (!current_user.conn)
+ return(False);
+
+ ChDir(OriginalDir);
+
+ if (initial_uid == 0)
+ {
+#ifdef HAVE_SETRESUID
+ setresuid(-1,getuid(),-1);
+ setresgid(-1,getgid(),-1);
+#else
+ if (seteuid(initial_uid) != 0)
+ setuid(initial_uid);
+ setgid(initial_gid);
+#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
+
+ current_user.uid = initial_uid;
+ current_user.gid = initial_gid;
+
+ if (ChDir(OriginalDir) != 0)
+ DEBUG( 0, ( "chdir(%s) failed in unbecome_user\n", OriginalDir ) );
+
+ DEBUG(5,("unbecome_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);
+}
+
+static struct current_user current_user_saved;
+static int become_root_depth;
+static pstring become_root_dir;
+
+/****************************************************************************
+This is used when we need to do a privilaged operation (such as mucking
+with share mode files) and temporarily need root access to do it. This
+call should always be paired with an unbecome_root() call immediately
+after the operation
+
+Set save_dir if you also need to save/restore the CWD
+****************************************************************************/
+void become_root(BOOL save_dir)
+{
+ if (become_root_depth) {
+ DEBUG(0,("ERROR: become root depth is non zero\n"));
+ }
+ if (save_dir)
+ GetWd(become_root_dir);
+
+ current_user_saved = current_user;
+ become_root_depth = 1;
+
+ become_uid(0);
+ become_gid(0);
+}
+
+/****************************************************************************
+When the privilaged operation is over call this
+
+Set save_dir if you also need to save/restore the CWD
+****************************************************************************/
+void unbecome_root(BOOL restore_dir)
+{
+ if (become_root_depth != 1) {
+ DEBUG(0,("ERROR: unbecome root depth is %d\n",
+ become_root_depth));
+ }
+
+ /* we might have done a become_user() while running as root,
+ if we have then become root again in order to become
+ non root! */
+ if (current_user.uid != 0) {
+ become_uid(0);
+ }
+
+ /* restore our gid first */
+ if (!become_gid(current_user_saved.gid)) {
+ DEBUG(0,("ERROR: Failed to restore gid\n"));
+ exit_server("Failed to restore gid");
+ }
+
+#ifdef HAVE_SETGROUPS
+ if (current_user_saved.ngroups > 0) {
+ if (setgroups(current_user_saved.ngroups,
+ current_user_saved.groups)<0)
+ DEBUG(0,("ERROR: setgroups call failed!\n"));
+ }
+#endif
+
+ /* now restore our uid */
+ if (!become_uid(current_user_saved.uid)) {
+ DEBUG(0,("ERROR: Failed to restore uid\n"));
+ exit_server("Failed to restore uid");
+ }
+
+ if (restore_dir)
+ ChDir(become_root_dir);
+
+ current_user = current_user_saved;
+
+ become_root_depth = 0;
+}
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/tests/.cvsignore b/source/tests/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/tests/.cvsignore
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/fcntl_lock.c b/source/tests/fcntl_lock.c
new file mode 100644
index 00000000000..c54479434e8
--- /dev/null
+++ b/source/tests/fcntl_lock.c
@@ -0,0 +1,78 @@
+/* test whether fcntl locking works on this system */
+
+#include <stdio.h>
+#include <stdlib.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.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, pid, ret, status=1;
+
+ if (!(pid=fork())) {
+ sleep(2);
+ fd = open(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_GETLK,&lock);
+
+ if ((ret == -1) ||
+ (lock.l_type == F_UNLCK)) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+ }
+
+ fd = open(DATA, O_RDWR|O_CREAT|O_TRUNC, 0600);
+
+ 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);
+
+ exit(status);
+}
diff --git a/source/tests/ftruncate.c b/source/tests/ftruncate.c
new file mode 100644
index 00000000000..8d5e8942e37
--- /dev/null
+++ b/source/tests/ftruncate.c
@@ -0,0 +1,24 @@
+/* test whether ftruncte() can extend a file */
+
+#include <unistd.h>
+#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..37990e010b8
--- /dev/null
+++ b/source/tests/getgroups.c
@@ -0,0 +1,62 @@
+/* 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
+ */
+
+#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..fb8a2a32d5f
--- /dev/null
+++ b/source/tests/shared_mmap.c
@@ -0,0 +1,66 @@
+/* this tests whether we can use a shared writeable mmap on a file -
+ as needed for the mmap varient of FAST_SHARE_MODES */
+
+#include <unistd.h>
+#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, pid;
+ 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..3db510495ae
--- /dev/null
+++ b/source/tests/summary.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+
+main()
+{
+#ifndef HAVE_FCNTL_LOCK
+ printf("ERROR: No locking available. Running Samba would be unsafe\n");
+ exit(1);
+#endif
+
+#if !(defined(HAVE_SYSV_IPC) || defined(HAVE_SHARED_MMAP))
+ printf("WARNING: no shared memory. Running with slow locking code\n");
+#endif
+
+#ifdef HAVE_TRAPDOOR_UID
+ printf("WARNING: trapdoor uid system - Samba may not operate correctly\n");
+#endif
+
+#if !(defined(HAVE_NETMASK_IFCONF) || defined(HAVE_NETMASK_IFREQ) || defined(HAVE_NETMASK_AIX))
+ printf("WARNING: No automated netmask determination - use an interfaces line\n");
+#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/sysv_ipc.c b/source/tests/sysv_ipc.c
new file mode 100644
index 00000000000..13956ec6f08
--- /dev/null
+++ b/source/tests/sysv_ipc.c
@@ -0,0 +1,86 @@
+/* this tests whether we can use a sysv shared memory segment
+ as needed for the sysv varient of FAST_SHARE_MODES */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+#define KEY 0x963796
+#define SEMKEY 0x963797
+#define SIZE (32*1024)
+
+#ifndef HAVE_UNION_SEMUN
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
+#endif
+
+
+main()
+{
+ int id, sem_id;
+ int *buf;
+ int count=7;
+ union semun su;
+
+#ifdef LINUX
+ if (sizeof(struct shmid_ds) == 52) {
+ printf("WARNING: You probably have a broken set of glibc2 include files - disabling sysv shared memory\n");
+ exit(1);
+ }
+#endif
+
+
+ sem_id = semget(SEMKEY, 1, IPC_CREAT|IPC_EXCL|0600);
+
+ if (sem_id == -1) exit(1);
+
+ su.val = 1;
+ semctl(sem_id, 0, IPC_RMID, su);
+
+ id = shmget(KEY, 0, 0);
+ if (id != -1) {
+ if (shmctl(id, IPC_RMID, 0) != 0) exit(1);
+ }
+
+ if (fork() == 0) {
+ /* uggh - need locking */
+ sleep(2);
+
+ /* get an existing area */
+ id = shmget(KEY, 0, 0);
+ if (id == -1) exit(1);
+
+ buf = (int *)shmat(id, 0, 0);
+ if (buf == (int *)-1) exit(1);
+
+
+ while (count-- && buf[6124] != 55732) sleep(1);
+
+ if (count <= 0) exit(1);
+
+ buf[1763] = 7268;
+ exit(0);
+ }
+
+ id = shmget(KEY, SIZE, IPC_CREAT | IPC_EXCL | 0600);
+ if (id == -1) exit(1);
+
+ buf = (int *)shmat(id, 0, 0);
+
+ if (buf == (int *)-1) exit(1);
+
+ buf[6124] = 55732;
+
+ while (count-- && buf[1763] != 7268) sleep(1);
+
+ shmctl(id, IPC_RMID, 0);
+
+ if (count <= 0) exit(1);
+ exit(0);
+}
diff --git a/source/tests/trapdoor.c b/source/tests/trapdoor.c
new file mode 100644
index 00000000000..83e10d06130
--- /dev/null
+++ b/source/tests/trapdoor.c
@@ -0,0 +1,25 @@
+/* test for a trapdoor uid system */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+main()
+{
+ if (getuid() != 0) {
+ fprintf(stderr,"ERROR: This test must be run as root - assuming non-trapdoor system\n");
+ exit(0);
+ }
+
+ if (seteuid(1) != 0) exit(1);
+ if (geteuid() != 1) exit(1);
+ if (seteuid(0) != 0) exit(1);
+ if (geteuid() != 0) exit(1);
+
+ if (setegid(1) != 0) exit(1);
+ if (getegid() != 1) exit(1);
+ if (setegid(0) != 0) exit(1);
+ if (getegid() != 0) exit(1);
+
+ 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/ubiqx/.cvsignore b/source/ubiqx/.cvsignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/ubiqx/.cvsignore
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/sys_include.h b/source/ubiqx/sys_include.h
new file mode 100644
index 00000000000..acfa5cdb849
--- /dev/null
+++ b/source/ubiqx/sys_include.h
@@ -0,0 +1,51 @@
+#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_
+
+/* 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..62d17d52555
--- /dev/null
+++ b/source/ubiqx/ubi_BinTree.c
@@ -0,0 +1,1080 @@
+/* ========================================================================== **
+ * 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.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.5 \n\
+\tDate: 1998/06/04 21:29:27 \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( 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( 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!
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ register int i;
+ register int btNodeSize = sizeof( ubi_btNode );
+
+ for( i = 0; i < btNodeSize; i++ ) /* Copy node internals to new node. */
+ ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+ (*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( 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( 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( 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.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr Q = NULL;
+
+ while( P )
+ {
+ Q = P;
+ P = P->Link[ whichway ];
+ }
+ return( Q );
+ } /* 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( P->Link[ whichway ] )
+ return( SubSlide( P->Link[ whichway ], (char)ubi_trRevWay(whichway) ) );
+ else
+ while( P->Link[ ubi_trPARENT ] )
+ {
+ if( (P->Link[ ubi_trPARENT ])->Link[ whichway ] == P )
+ 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( 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( 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( !(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 (!(*OldNode)) /* The easy one: we have a space for a new node! */
+ {
+ if (!(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( 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 (!(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( (DeadNode->Link[ubi_trLEFT]) && (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 (DeadNode->Link[ubi_trPARENT])
+ parentp = &((DeadNode->Link[ubi_trPARENT])->Link[(int)(DeadNode->gender)]);
+ else
+ parentp = &( RootPtr->root );
+
+ /* 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( 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( 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.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* If our starting point is invalid, return NULL. */
+ if( !p || ubi_trAbNormal( (*(RootPtr->cmp))( MatchMe, p ) != ubi_trEQUAL ) )
+ 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.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ /* If our starting point is invalid, return NULL. */
+ if( !p || ubi_trAbNormal( (*(RootPtr->cmp))( MatchMe, p ) != ubi_trEQUAL ) )
+ return( NULL );
+ return( Border( RootPtr, MatchMe, p, ubi_trRIGHT ) );
+ } /* ubi_btLastOf */
+
+ubi_trBool 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 boolean value. FALSE if the tree is empty, otherwise TRUE.
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p;
+
+ if( !(p = ubi_btFirst( RootPtr->root )) ) return( ubi_trFALSE );
+
+ while( p )
+ {
+ (*EachNode)( p, UserData );
+ p = ubi_btNext( p );
+ }
+ return( ubi_trTRUE );
+ } /* ubi_btTraverse */
+
+ubi_trBool ubi_btKillTree( ubi_btRootPtr RootPtr,
+ ubi_btKillNodeRtn FreeNode )
+ /* ------------------------------------------------------------------------ **
+ * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+ * structure. Note that this function will return FALSE if either parameter
+ * is NULL.
+ *
+ * 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: A boolean value. FALSE if either input parameter was NULL, else
+ * TRUE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+ {
+ ubi_btNodePtr p, q;
+
+ if( !(RootPtr) || !(FreeNode) )
+ return( ubi_trFALSE );
+
+ p = ubi_btFirst( RootPtr->root );
+ while( p )
+ {
+ q = p;
+ while( q->Link[ubi_trRIGHT] )
+ q = SubSlide( q->Link[ubi_trRIGHT], ubi_trLEFT );
+ p = q->Link[ubi_trPARENT];
+ if( p )
+ p->Link[ ((p->Link[ubi_trLEFT] == q)?ubi_trLEFT:ubi_trRIGHT) ] = NULL;
+ (*FreeNode)((void *)q);
+ }
+
+ (void)ubi_btInitTree( RootPtr,
+ RootPtr->cmp,
+ RootPtr->flags );
+ return( ubi_trTRUE );
+ } /* 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..9b7cda4bf23
--- /dev/null
+++ b/source/ubiqx/ubi_BinTree.h
@@ -0,0 +1,800 @@
+#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.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))
+
+/* -------------------------------------------------------------------------- **
+ * A quickie for consistency.
+ * ubi_trCount() - Given a pointer to a tree root, this macro returns the
+ * number of nodes currently in the tree.
+ *
+ * -------------------------------------------------------------------------- **
+ */
+
+#define ubi_trCount( R ) (((ubi_trRootPtr)(R))->count)
+
+/* -------------------------------------------------------------------------- **
+ * 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.
+ * ------------------------------------------------------------------------ **
+ */
+
+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.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool 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 boolean value. FALSE if the tree is empty, otherwise TRUE.
+ * ------------------------------------------------------------------------ **
+ */
+
+ubi_trBool ubi_btKillTree( ubi_btRootPtr RootPtr,
+ ubi_btKillNodeRtn FreeNode );
+ /* ------------------------------------------------------------------------ **
+ * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+ * structure. Note that this function will return FALSE if either parameter
+ * is NULL.
+ *
+ * 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: A boolean value. FALSE if either input parameter was NULL, else
+ * TRUE.
+ *
+ * ------------------------------------------------------------------------ **
+ */
+
+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..f6081374ef9
--- /dev/null
+++ b/source/ubiqx/ubi_Cache.c
@@ -0,0 +1,502 @@
+/* ========================================================================== **
+ * 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_trKillNodeTrn. 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.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.3 \n\
+\tDate: 1998/06/03 18:00:15 \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..76aab3172e5
--- /dev/null
+++ b/source/ubiqx/ubi_Cache.h
@@ -0,0 +1,409 @@
+#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_trKillNodeTrn. 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.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..ad8d568658d
--- /dev/null
+++ b/source/ubiqx/ubi_SplayTree.c
@@ -0,0 +1,509 @@
+/* ========================================================================== **
+ * 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.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.4 \n\
+\tDate: 1998/06/04 21:29:27 \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..0b62f7f7e79
--- /dev/null
+++ b/source/ubiqx/ubi_SplayTree.h
@@ -0,0 +1,371 @@
+#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.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_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..c780bd1df84
--- /dev/null
+++ b/source/ubiqx/ubi_dLinkList.c
@@ -0,0 +1,165 @@
+/* ========================================================================== **
+ * 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.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_slRemove() 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..548f8e5200d
--- /dev/null
+++ b/source/ubiqx/ubi_dLinkList.h
@@ -0,0 +1,236 @@
+#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.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_slRemove() 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..25eb5f7e41e
--- /dev/null
+++ b/source/ubiqx/ubi_sLinkList.c
@@ -0,0 +1,181 @@
+/* ========================================================================== **
+ * 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.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_slRemove() function, by necessity, removed 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_slRemove( ubi_slListPtr ListPtr, ubi_slNodePtr After )
+ /* ------------------------------------------------------------------------ **
+ * Remove the node followng <After>. If <After> is NULL, remove from the
+ * head of the list.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ * After - 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;
+
+ After = After ? After : (ubi_slNodePtr)ListPtr;
+ DelNode = After->Next;
+ if( DelNode )
+ {
+ if( !(DelNode->Next) )
+ ListPtr->Tail = After;
+ After->Next = DelNode->Next;
+ (ListPtr->count)--;
+ }
+ return( DelNode );
+ } /* ubi_slRemove */
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_sLinkList.h b/source/ubiqx/ubi_sLinkList.h
new file mode 100644
index 00000000000..1f331cd5b94
--- /dev/null
+++ b/source/ubiqx/ubi_sLinkList.h
@@ -0,0 +1,248 @@
+#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.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_slRemove() function, by necessity, removed 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_slRemove( (ubi_slListPtr)(L), NULL )
+
+#define ubi_slRemNext( L, N ) \
+ ubi_slRemove( (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_slRemove( ubi_slListPtr ListPtr, ubi_slNodePtr After );
+ /* ------------------------------------------------------------------------ **
+ * Remove the node followng <After>. If <After> is NULL, remove from the
+ * head of the list.
+ *
+ * Input: ListPtr - A pointer to the list from which the node is to be
+ * removed.
+ * After - 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/make_printerdef.c b/source/utils/make_printerdef.c
new file mode 100644
index 00000000000..c64ce64bbf5
--- /dev/null
+++ b/source/utils/make_printerdef.c
@@ -0,0 +1,510 @@
+ /*
+ 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;
+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(s,'%')) != NULL) {
+ if (!(LString2 = strchr(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(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';
+ pstrcpy(value,temp+i+1);
+ return (value);
+}
+
+static void build_subdir(void)
+{
+ int i=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
+
+ if (strcmp(data,"11")==0) {
+ pstrcpy(sub_dir[i][0],entry);
+ pstrcpy(sub_dir[i][1],"");
+ }
+ if (strcmp(data,"23")==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) {
+ 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++;
+ }
+ }
+#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) {
+ 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) {
+ 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;
+ }
+ 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_
+ * 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). This may still be wrong but at least I get the same list
+ * of files as seen on a printer test page.
+ */
+ part = strchr(buffer[i],'=');
+ if (part) {
+ *part = '\0';
+ while (--part > buffer[i])
+ if ((*part == ' ') || (*part =='\t')) *part = '\0';
+ else break;
+ } else {
+ part = strchr(buffer[i],',');
+ if (part) {
+ if ((mpart = strrchr(part+1,','))!=NULL) {
+ pstrcpy(buffer[i],mpart+1);
+ } else
+ *part = '\0';
+ while (--part > buffer[i])
+ if ((*part == ' ') || (*part =='\t')) *part = '\0';
+ else break;
+ }
+ }
+ 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++;
+ }
+ }
+ part=strtok(NULL,",");
+ }
+ 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;
+ 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);
+ 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);
+ i++;
+ }
+ }
+
+ if (languagemonitor) {
+ temp = strtok(languagemonitor,",");
+ if (*temp == '"') ++temp;
+ pstrcpy(languagemonitor,temp);
+ if ((temp = strchr(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)");
+ 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=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/make_smbcodepage.c b/source/utils/make_smbcodepage.c
new file mode 100644
index 00000000000..0653fd31f1a
--- /dev/null
+++ b/source/utils/make_smbcodepage.c
@@ -0,0 +1,472 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Create codepage files from codepage_def.XXX files.
+
+ Copyright (C) Jeremy Allison 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"
+
+static char *prog_name = NULL;
+
+/*
+ * Print program usage and die.
+ */
+
+static void codepage_usage(char *progname)
+{
+ fprintf(stderr, "Usage is : %s [c|d] <codepage> <inputfile> <outputfile>\n",
+ progname);
+ exit(1);
+}
+
+/*
+ * Read a line from a buffer into a line buffer. Ensure null
+ * terminated.
+ */
+
+static void read_line( char **buf, char *line_buf, int size)
+{
+ char *p = *buf;
+ int num = 0;
+
+ for(; *p && (*p != '\n'); p++)
+ {
+ if(num < (size - 1))
+ line_buf[num++] = *p;
+ }
+ if(*p)
+ p++; /* Go past the '\n' */
+ line_buf[num] = '\0';
+ *buf = p;
+}
+
+/*
+ * Strip comment lines and blank lines from the data.
+ * Copies into a new buffer and frees the old.
+ * Returns the number of lines copied.
+ */
+
+static int clean_data( char **buf, uint32 *size)
+{
+ pstring linebuf;
+ char *p = *buf;
+ int num_lines = 0;
+ char *newbuf = (char *)malloc( *size + 1);
+ char *newbuf_p = NULL;
+
+ if(newbuf == NULL)
+ {
+ fprintf(stderr, "%s: malloc fail for size %d.\n", prog_name, *size + 1);
+ exit(1);
+ }
+
+ newbuf_p = newbuf;
+ *newbuf_p = '\0';
+
+ while( *p )
+ {
+ char *cp;
+
+ read_line( &p, linebuf, sizeof(linebuf));
+ /* Null terminate after comment. */
+ if((cp = strchr( linebuf, '#'))!= NULL)
+ *cp = '\0';
+
+ for(cp = linebuf;*cp && isspace(*cp); cp++)
+ ;
+
+ if(*cp == '\0')
+ continue;
+
+ safe_strcpy(newbuf_p, cp, *size - (newbuf_p - newbuf));
+ num_lines++;
+ newbuf_p += (strlen(newbuf_p) + 1);
+ }
+
+ free(*buf);
+ *buf = newbuf;
+ return num_lines;
+}
+
+/*
+ * Parse a byte from a codepage file.
+ */
+
+static BOOL parse_byte(char *buf, unsigned char *bp)
+{
+ unsigned int b;
+ char *endptr = NULL;
+
+ b = (unsigned int)strtol(buf, &endptr, 0);
+ if(endptr == buf || b > 255)
+ return False;
+
+ *bp = (unsigned char)b;
+ return True;
+}
+
+/*
+ * Parse a bool from a codepage file.
+ */
+
+static BOOL parse_bool(char *buf, unsigned char *bp)
+{
+ if(isdigit((int)*buf))
+ {
+ char *endptr = NULL;
+
+ *bp = (unsigned char)strtol(buf, &endptr, 0);
+ if(endptr == buf )
+ return False;
+ if(*bp != 0)
+ *bp = 1;
+ } else {
+ if(strcasecmp(buf, "True") && strcasecmp(buf, "False"))
+ return False;
+ if(strcasecmp(buf, "True")==0)
+ *bp = 1;
+ else
+ *bp = 0;
+ }
+ return True;
+}
+
+/*
+ * Print a parse error and exit.
+ */
+
+static void parse_error(char *buf, char *msg)
+{
+ fprintf(stderr, "%s: %s whilst parsing line \n%s\n", prog_name,
+ msg, buf);
+ exit(1);
+}
+
+/*
+ * Create a compiled codepage file from a codepage definition file.
+ */
+
+static int do_compile(int codepage, char *input_file, char *output_file)
+{
+ FILE *fp = NULL;
+ uint32 size = 0;
+ char *buf = NULL;
+ char output_buf[CODEPAGE_HEADER_SIZE + 4 * MAXCODEPAGELINES];
+ int num_lines = 0;
+ int i = 0;
+ SMB_STRUCT_STAT st;
+
+ /* Get the size of the input file. Read the entire thing into memory. */
+ if(sys_stat((char *)input_file, &st)!= 0)
+ {
+ fprintf(stderr, "%s: failed to get the file size for file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ size = (uint32)st.st_size;
+
+ /* I don't believe these things should be bigger than 100k :-) */
+ if(size > 100*1024)
+ {
+ fprintf(stderr, "%s: filesize %d is too large for a codepage definition file. \
+The maximum size I will believe is 100k.\n", prog_name, size);
+ exit(1);
+ }
+
+ if((fp = fopen(input_file, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s for input.\n", prog_name, input_file);
+ exit(1);
+ }
+
+ /* As we will be reading text, allocate one more byte for a '\0' */
+ if((buf = (char *)malloc( size + 1 )) == NULL)
+ {
+ fprintf(stderr, "%s: malloc fail for size %d.\n", prog_name, size + 1);
+ fclose(fp);
+ exit(1);
+ }
+
+ if(fread( buf, 1, size, fp) != size)
+ {
+ fprintf(stderr, "%s: read failed for file %s. Error was %s.\n", prog_name,
+ input_file, strerror(errno));
+ free((char *)buf);
+ fclose(fp);
+ exit(1);
+ }
+
+ /* Null terminate the text read. */
+ buf[size] = '\0';
+
+ /* Go through the data line by line, strip out comments (anything
+ after a '#' to end-of-line) and blank lines. The rest should be
+ the codepage data.
+ */
+
+ num_lines = clean_data( &buf, &size);
+
+ /* There can be a maximum of MAXCODEPAGELINES lines. */
+ if(num_lines > MAXCODEPAGELINES)
+ {
+ fprintf(stderr, "%s: There can be a maximum %d lines of data in a codepage \
+definition file. File %s has %d.\n", prog_name, MAXCODEPAGELINES, input_file, num_lines);
+ exit(1);
+ }
+
+ /* Setup the output file header. */
+ SSVAL(output_buf,CODEPAGE_VERSION_OFFSET,CODEPAGE_FILE_VERSION_ID);
+ SSVAL(output_buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET,(uint16)codepage);
+ SIVAL(output_buf,CODEPAGE_LENGTH_OFFSET,(num_lines * 4));
+
+ /* Now convert the lines into the compiled form. */
+ for(i = 0; i < num_lines; i++)
+ {
+ char token_buf[512];
+ char *p = buf;
+ unsigned char b = 0;
+
+ /* Get the 'lower' value. */
+ if(!next_token(&p, token_buf, NULL, sizeof(token_buf)))
+ parse_error(buf, "cannot parse first value");
+ if(!parse_byte( token_buf, &b))
+ parse_error(buf, "first value doesn't resolve to a byte");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4),b);
+
+ /* Get the 'upper' value. */
+ if(!next_token(&p, token_buf, NULL, sizeof(token_buf)))
+ parse_error(buf, "cannot parse second value");
+ if(!parse_byte( token_buf, &b))
+ parse_error(buf, "second value doesn't resolve to a byte");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4) + 1,b);
+
+ /* Get the 'upper to lower' value. */
+ if(!next_token(&p, token_buf, NULL, sizeof(token_buf)))
+ parse_error(buf, "cannot parse third value");
+ if(!parse_bool( token_buf, &b))
+ parse_error(buf, "third value doesn't resolve to a boolean");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4) + 2,b);
+
+ /* Get the 'lower to upper' value. */
+ if(!next_token(&p, token_buf, NULL, sizeof(token_buf)))
+ parse_error(buf, "cannot parse fourth value");
+ if(!parse_bool( token_buf, &b))
+ parse_error(buf, "fourth value doesn't resolve to a boolean");
+
+ /* Add this to the output buffer. */
+ SCVAL(output_buf,CODEPAGE_HEADER_SIZE+(i*4) + 3,b);
+
+ buf += (strlen(buf) + 1);
+ }
+
+ /* Now write out the output_buf. */
+ if((fp = fopen(output_file, "w"))==NULL)
+ {
+ fprintf(stderr, "%s: Cannot open output file %s. Error was %s.\n",
+ prog_name, output_file, strerror(errno));
+ exit(1);
+ }
+
+ if(fwrite(output_buf, 1, CODEPAGE_HEADER_SIZE + (num_lines*4), fp) !=
+ CODEPAGE_HEADER_SIZE + (num_lines*4))
+ {
+ fprintf(stderr, "%s: Cannot write output file %s. Error was %s.\n",
+ prog_name, output_file, strerror(errno));
+ exit(1);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+/*
+ * Placeholder for now.
+ */
+
+static int do_decompile( int codepage, char *input_file, char *output_file)
+{
+ uint32 size = 0;
+ SMB_STRUCT_STAT st;
+ char header_buf[CODEPAGE_HEADER_SIZE];
+ char *buf = NULL;
+ FILE *fp = NULL;
+ int num_lines = 0;
+ int i = 0;
+
+ /* Get the size of the input file. Read the entire thing into memory. */
+ if(sys_stat((char *)input_file, &st)!= 0)
+ {
+ fprintf(stderr, "%s: failed to get the file size for file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ size = (uint32)st.st_size;
+
+ if( size < CODEPAGE_HEADER_SIZE || size > (CODEPAGE_HEADER_SIZE + 256))
+ {
+ fprintf(stderr, "%s: file %s is an incorrect size for a \
+code page file.\n", prog_name, input_file);
+ exit(1);
+ }
+
+ /* Read the first 8 bytes of the codepage file - check
+ the version number and code page number. All the data
+ is held in little endian format.
+ */
+
+ if((fp = fopen( input_file, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ if(fread( header_buf, 1, CODEPAGE_HEADER_SIZE, fp)!=CODEPAGE_HEADER_SIZE)
+ {
+ fprintf(stderr, "%s: cannot read header from file %s. Error was %s\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ /* Check the version value */
+ if(SVAL(header_buf,CODEPAGE_VERSION_OFFSET) != CODEPAGE_FILE_VERSION_ID)
+ {
+ fprintf(stderr, "%s: filename %s has incorrect version id. \
+Needed %hu, got %hu.\n",
+ prog_name, input_file, (uint16)CODEPAGE_FILE_VERSION_ID,
+ SVAL(header_buf,CODEPAGE_VERSION_OFFSET));
+ exit(1);
+ }
+
+ /* Check the codepage matches */
+ if(SVAL(header_buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET) != (uint16)codepage)
+ {
+ fprintf(stderr, "%s: filename %s has incorrect codepage. \
+Needed %hu, got %hu.\n",
+ prog_name, input_file, (uint16)codepage,
+ SVAL(header_buf,CODEPAGE_CLIENT_CODEPAGE_OFFSET));
+ exit(1);
+ }
+
+ /* Check the length is correct. */
+ if(IVAL(header_buf,CODEPAGE_LENGTH_OFFSET) !=
+ (unsigned int)(size - CODEPAGE_HEADER_SIZE))
+ {
+ fprintf(stderr, "%s: filename %s has incorrect size headers. \
+Needed %u, got %u.\n", prog_name, input_file, size - CODEPAGE_HEADER_SIZE,
+ IVAL(header_buf,CODEPAGE_LENGTH_OFFSET));
+ exit(1);
+ }
+
+ size -= CODEPAGE_HEADER_SIZE; /* Remove header */
+
+ /* Make sure the size is a multiple of 4. */
+ if((size % 4 ) != 0)
+ {
+ fprintf(stderr, "%s: filename %s has a codepage size not a \
+multiple of 4.\n", prog_name, input_file);
+ exit(1);
+ }
+
+ /* Allocate space for the code page file and read it all in. */
+ if((buf = (char *)malloc( size )) == NULL)
+ {
+ fprintf (stderr, "%s: malloc fail for size %d.\n",
+ prog_name, size );
+ exit(1);
+ }
+
+ if(fread( buf, 1, size, fp)!=size)
+ {
+ fprintf(stderr, "%s: read fail on file %s. Error was %s.\n",
+ prog_name, input_file, strerror(errno));
+ exit(1);
+ }
+
+ fclose(fp);
+
+ /* Now dump the codepage into an ascii file. */
+ if((fp = fopen(output_file, "w")) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s. Error was %s\n",
+ prog_name, output_file, strerror(errno));
+ exit(1);
+ }
+
+ fprintf(fp, "#\n# Codepage definition file for IBM Code Page %d.\n#\n",
+ codepage);
+ fprintf(fp, "# This file was automatically generated.\n#\n");
+ fprintf(fp, "# defines lower->upper mapping.\n");
+ fprintf(fp, "#\n#The columns are :\n# lower\tupper\tu-t-l\tl-t-u\n#\n");
+
+ num_lines = size / 4;
+ for( i = 0; i < num_lines; i++)
+ {
+ fprintf(fp, "0x%02X\t0x%02X\t%s\t%s\n", CVAL(buf, (i*4)), CVAL(buf, (i*4)+1),
+ CVAL(buf, (i*4)+2) ? "True" : "False",
+ CVAL(buf, (i*4)+3) ? "True" : "False");
+ }
+ fclose(fp);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int codepage = 0;
+ char *input_file = NULL;
+ char *output_file = NULL;
+ BOOL compile = False;
+
+ prog_name = argv[0];
+
+ if(argc != 5)
+ codepage_usage(prog_name);
+
+ if(argv[1][0] != 'c' && argv[1][0] != 'C' && argv[1][0] != 'd' &&
+ argv[1][0] != 'D')
+ codepage_usage(prog_name);
+
+ input_file = argv[3];
+ output_file = argv[4];
+
+ /* Are we compiling or decompiling. */
+ if(argv[1][0] == 'c' || argv[1][0] == 'C')
+ compile = True;
+
+ /* Convert the second argument into a client codepage value. */
+ if((codepage = atoi(argv[2])) == 0)
+ {
+ fprintf(stderr, "%s: %s is not a valid codepage.\n", prog_name, argv[2]);
+ exit(1);
+ }
+
+ if(compile)
+ return do_compile( codepage, input_file, output_file);
+ else
+ return do_decompile( codepage, input_file, output_file);
+}
diff --git a/source/utils/nmblookup.c b/source/utils/nmblookup.c
index aa431733322..477d6590f02 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,39 +20,30 @@
*/
-#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 got_bcast = False;
+extern struct in_addr ipzero;
int ServerFD= -1;
+int RootPort = 0;
+
/****************************************************************************
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),
+ 3,
+ interpret_addr(lp_socket_address()) );
if (ServerFD == -1)
return(False);
@@ -69,24 +60,9 @@ static BOOL open_sockets(void)
****************************************************************************/
static BOOL init_structs(void )
{
- struct in_addr myip;
-
- if (!get_myname(myhostname,&myip))
+ if (!get_myname(myhostname,NULL))
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);
-
- DEBUG(2,("Using broadcast %s\n",inet_ntoa(bcast_ip)));
- }
- }
-
return True;
}
@@ -99,8 +75,12 @@ static void usage(void)
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-U unicast address the address to use for unicast\n");
printf("\t-M searches for a master browser\n");
+ printf("\t-R set recursion desired in packet\n");
printf("\t-S lookup node status as well\n");
+ printf("\t-r Use root port 137 (Win95 only replies to this)\n");
+ printf("\t-A Do a node status on <name> as an IP Address\n");
printf("\n");
}
@@ -111,14 +91,20 @@ 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;
-
+ static pstring servicesf = CONFIGFILE;
+ struct in_addr bcast_addr;
+ BOOL use_bcast = True;
+ BOOL got_bcast = False;
+ BOOL lookup_by_ip = False;
+ BOOL recursion_desired = False;
+
DEBUGLEVEL = 1;
*lookup = 0;
@@ -128,18 +114,23 @@ int main(int argc,char *argv[])
charset_initialise();
- while ((opt = getopt(argc, argv, "p:d:B:i:SMh")) != EOF)
+ while ((opt = getopt(argc, argv, "d:B:U:i:s:SMrhAR")) != EOF)
switch (opt)
{
case 'B':
- {
- unsigned long a = interpret_addr(optarg);
- putip((char *)&bcast_ip,(char *)&a);
- got_bcast = True;
- }
+ iface_set_default(NULL,optarg,NULL);
+ bcast_addr = *interpret_addr2(optarg);
+ got_bcast = True;
+ use_bcast = True;
+ break;
+ case 'U':
+ iface_set_default(NULL,optarg,NULL);
+ bcast_addr = *interpret_addr2(optarg);
+ got_bcast = True;
+ use_bcast = False;
break;
case 'i':
- strcpy(scope,optarg);
+ fstrcpy(scope,optarg);
strupper(scope);
break;
case 'M':
@@ -148,13 +139,25 @@ int main(int argc,char *argv[])
case 'S':
find_status = True;
break;
+ case 'R':
+ recursion_desired = True;
+ break;
case 'd':
DEBUGLEVEL = atoi(optarg);
break;
+ case 's':
+ pstrcpy(servicesf, optarg);
+ break;
+ case 'r':
+ RootPort = -1;
+ break;
case 'h':
usage();
exit(0);
break;
+ case 'A':
+ lookup_by_ip = True;
+ break;
default:
usage();
exit(1);
@@ -166,23 +169,42 @@ int main(int argc,char *argv[])
}
init_structs();
+
+ if (!lp_load(servicesf,True,False,False)) {
+ fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
+ }
+
+ load_interfaces();
if (!open_sockets()) return(1);
- DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_ip)));
+ if (!got_bcast)
+ bcast_addr = *iface_bcast(ipzero);
+
+ DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_addr)));
for (i=optind;i<argc;i++)
- {
- BOOL bcast = True;
- int retries = 2;
+ {
+ int j, count;
char *p;
struct in_addr ip;
+ struct in_addr *ip_list;
- strcpy(lookup,argv[i]);
+ fstrcpy(lookup,argv[i]);
+
+ if(lookup_by_ip)
+ {
+ fstrcpy(lookup,"*");
+ ip = *interpret_addr2(argv[i]);
+ printf("Looking up status of %s\n",inet_ntoa(ip));
+ name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
+ printf("\n");
+ 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;
@@ -192,26 +214,27 @@ int main(int argc,char *argv[])
p = strchr(lookup,'#');
if (p) {
- *p = 0;
- sscanf(p+1,"%x",&lookup_type);
- bcast = False;
- retries = 1;
+ *p = 0;
+ sscanf(p+1,"%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");
- }
+ if ((ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,recursion_desired,
+ bcast_addr,&count,NULL))) {
+ for (j=0;j<count;j++)
+ 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) {
+ printf("Looking up status of %s\n",inet_ntoa(ip_list[0]));
+ name_status(ServerFD,lookup,lookup_type,True,ip_list[0],NULL,NULL,NULL);
+ printf("\n");
+ }
} else {
- printf("couldn't find name %s\n",lookup);
+ printf("name_query failed to find name %s\n", lookup);
}
- }
-
+ }
+
return(0);
}
diff --git a/source/utils/smbpasswd.c b/source/utils/smbpasswd.c
index 167eb2ed5f3..e5e5424a2b8 100644
--- a/source/utils/smbpasswd.c
+++ b/source/utils/smbpasswd.c
@@ -1,8 +1,6 @@
-#ifdef SMB_PASSWD
-
/*
* Unix SMB/Netbios implementation. Version 1.9. smbpasswd module. Copyright
- * (C) Jeremy Allison 1995.
+ * (C) Jeremy Allison 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
@@ -20,437 +18,653 @@
*/
#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 scope;
+extern pstring myhostname;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+
+static char *prog_name;
-static int gethexpwd(char *p, char *pwd)
+/*********************************************************
+ Print command usage on stderr and die.
+**********************************************************/
+
+static void usage(char *name, BOOL is_root)
{
- 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);
+ if(is_root)
+ fprintf(stderr, "Usage is : %s [-D DEBUGLEVEL] [-a] [-d] [-e] [-m] [-n] [username] [password]\n\
+%s: [-R <name resolve order>] [-D DEBUGLEVEL] [-j DOMAINNAME] [-r machine] [-U remote_username] [username] [password]\n%s: [-h]\n", name, name, name);
+ else
+ fprintf(stderr, "Usage is : %s [-h] [-D DEBUGLEVEL] [-r machine] [-U remote_username] [password]\n", name);
+ exit(1);
}
-struct smb_passwd *
-_my_get_smbpwnam(FILE * fp, char *name, BOOL * valid_old_pwd,
- BOOL *got_valid_nt_entry, long *pwd_seekpos)
+/*********************************************************
+Join a domain.
+**********************************************************/
+
+static int join_domain( char *domain, char *remote)
{
- char linebuf[256];
- unsigned char c;
- unsigned char *p;
- long uidval;
- long linebuf_len;
-
- /*
- * Scan the file, a line at a time and check if the name matches.
- */
- while (!feof(fp)) {
- linebuf[0] = '\0';
- *pwd_seekpos = ftell(fp);
-
- 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;
- }
- } 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.
- */
-
- 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;
-
- /* User name matches - get uid and password */
- p++; /* Go past ':' */
- if (!isdigit(*p))
- return (False);
-
- uidval = atoi((char *) p);
- while (*p && isdigit(*p))
- p++;
-
- if (*p != ':')
- 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++;
- *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 (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
- return (False);
-
- if (p[32] != ':')
- return (False);
-
- 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;
- }
-
- 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;
- }
- }
- return &pw_buf;
- }
- return NULL;
+ pstring remote_machine;
+ fstring trust_passwd;
+ unsigned char orig_trust_passwd_hash[16];
+ BOOL ret;
+
+ pstrcpy(remote_machine, remote ? remote : "");
+ fstrcpy(trust_passwd, global_myname);
+ strlower(trust_passwd);
+ E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash);
+
+ /* Ensure that we are not trying to join a
+ domain if we are locally set up as a domain
+ controller. */
+
+ if(lp_domain_controller() && strequal(lp_workgroup(), domain)) {
+ fprintf(stderr, "%s: Cannot join domain %s as we already configured as \
+domain controller for that domain.\n", prog_name, domain);
+ return 1;
+ }
+
+ /*
+ * Create the machine account password file.
+ */
+ if(!trust_password_lock( domain, global_myname, True)) {
+ fprintf(stderr, "%s: unable to open the machine account password file for \
+machine %s in domain %s.\n", prog_name, global_myname, domain);
+ return 1;
+ }
+
+ /*
+ * Write the old machine account password.
+ */
+
+ if(!set_trust_account_password( orig_trust_passwd_hash)) {
+ fprintf(stderr, "%s: unable to write the machine account password for \
+machine %s in domain %s.\n", prog_name, global_myname, domain);
+ trust_password_unlock();
+ return 1;
+ }
+
+ /*
+ * If we are given a remote machine assume this is the PDC.
+ */
+
+ if(remote == NULL)
+ pstrcpy(remote_machine, lp_passwordserver());
+
+ if(!*remote_machine) {
+ fprintf(stderr, "%s: No password server list given in smb.conf - \
+unable to join domain.\n", prog_name);
+ trust_password_unlock();
+ return 1;
+ }
+
+ ret = change_trust_account_password( domain, remote_machine);
+ trust_password_unlock();
+
+ if(!ret) {
+ trust_password_delete( domain, global_myname);
+ fprintf(stderr,"%s: Unable to join domain %s.\n", prog_name, domain);
+ } else {
+ printf("%s: Joined domain %s.\n", prog_name, domain);
+ }
+
+ return (int)ret;
}
-/*
- * Print command usage on stderr and die.
- */
-void
-usage(char *name)
+/*************************************************************
+ Utility function to create password hashes.
+*************************************************************/
+
+static void create_new_hashes( char *new_passwd, uchar *new_p16, uchar *new_nt_p16)
{
- fprintf(stderr, "Usage is : %s [username]\n", name);
- exit(1);
+ memset(new_nt_p16, '\0', 16);
+ E_md4hash((uchar *) new_passwd, new_nt_p16);
+
+ /* Mangle the password into Lanman format */
+ new_passwd[14] = '\0';
+ strupper(new_passwd);
+
+ /*
+ * Calculate the SMB (lanman) hash functions of the new password.
+ */
+
+ memset(new_p16, '\0', 16);
+ E_P16((uchar *) new_passwd, new_p16);
+}
+
+/*************************************************************
+ Utility function to prompt for new password.
+*************************************************************/
+
+static void prompt_for_new_password(char *new_passwd)
+{
+ char *p;
+
+ 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 (strncmp(p, new_passwd, sizeof(fstring)-1))
+ {
+ fprintf(stderr, "%s: Mismatch - password unchanged.\n", prog_name);
+ exit(1);
+ }
+
+ if (new_passwd[0] == '\0') {
+ printf("Password not set\n");
+ exit(0);
+ }
}
+/*********************************************************
+ Start here.
+**********************************************************/
+
int main(int argc, char **argv)
{
+ extern char *optarg;
+ extern int optind;
+ extern int DEBUGLEVEL;
int real_uid;
- struct passwd *pwd;
+ struct passwd *pwd = NULL;
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];
+ int ch;
+ int err;
+ BOOL is_root = False;
+ pstring user_name;
+ BOOL remote_user_name = False;
+ char *remote_machine = NULL;
+ BOOL add_user = False;
+ BOOL got_new_pass = False;
+ BOOL trust_account = False;
+ BOOL disable_user = False;
+ BOOL enable_user = False;
+ BOOL set_no_password = False;
+ BOOL joining_domain = False;
+ char *new_domain = NULL;
+ pstring servicesf = CONFIGFILE;
+ void *vp;
+ struct nmb_name calling, called;
- setup_logging(argv[0],True);
+
+ new_passwd[0] = '\0';
+ user_name[0] = '\0';
+
+ memset(old_passwd, '\0', sizeof(old_passwd));
+ memset(new_passwd, '\0', sizeof(new_passwd));
+
+ prog_name = argv[0];
+
+ TimeInit();
+
+ setup_logging(prog_name,True);
charset_initialise();
-
-#ifndef DEBUG_PASSWORD
- /* Check the effective uid */
- if (geteuid() != 0) {
- fprintf(stderr, "%s: Must be setuid root.\n", argv[0]);
+
+ if(!initialize_password_db()) {
+ fprintf(stderr, "%s: Can't setup password database vectors.\n", prog_name);
exit(1);
}
-#endif
-
+
+ if (!lp_load(servicesf,True,False,False)) {
+ fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n", prog_name, servicesf);
+ exit(1);
+ }
+
+ if(!get_myname(myhostname,NULL)) {
+ fprintf(stderr, "%s: unable to get my hostname.\n", prog_name );
+ exit(1);
+ }
+
+ /*
+ * Set the machine NETBIOS name if not already
+ * set from the config file.
+ */
+
+ if (!*global_myname)
+ {
+ fstrcpy( global_myname, myhostname );
+ p = strchr( global_myname, '.' );
+ if (p)
+ *p = 0;
+ }
+ strupper( global_myname );
+
+ codepage_initialise(lp_client_code_page());
+
/* 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]);
+ /* Check the effective uid */
+ if ((geteuid() == 0) && (real_uid != 0)) {
+ fprintf(stderr, "%s: Must *NOT* be setuid root.\n", prog_name);
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';
+
+ is_root = (real_uid == 0);
+
+ while ((ch = getopt(argc, argv, "adehmnj:r:R:D:U:")) != EOF) {
+ switch(ch) {
+ case 'a':
+ if(is_root)
+ add_user = True;
+ else
+ usage(prog_name, is_root);
+ break;
+ case 'd':
+ if(is_root) {
+ disable_user = True;
+ got_new_pass = True;
+ fstrcpy(new_passwd, "XXXXXX");
+ } else
+ usage(prog_name, is_root);
+ break;
+ case 'e':
+ if(is_root) {
+ enable_user = True;
+ got_new_pass = True;
+ fstrcpy(new_passwd, "XXXXXX");
+ } else
+ usage(prog_name, is_root);
+ break;
+ case 'D':
+ DEBUGLEVEL = atoi(optarg);
+ break;
+ case 'n':
+ if(is_root) {
+ set_no_password = True;
+ got_new_pass = True;
+ fstrcpy(new_passwd, "NO PASSWORD");
+ } else
+ usage(prog_name, is_root);
+ case 'r':
+ remote_machine = optarg;
+ break;
+ case 'R':
+ if(is_root) {
+ lp_set_name_resolve_order(optarg);
+ break;
+ } else
+ usage(prog_name, is_root);
+ case 'm':
+ if(is_root) {
+ trust_account = True;
+ } else
+ usage(prog_name, is_root);
+ break;
+ case 'j':
+ if(is_root) {
+ new_domain = optarg;
+ strupper(new_domain);
+ joining_domain = True;
+ } else
+ usage(prog_name, is_root);
+ break;
+ case 'U':
+ remote_user_name = True;
+ pstrcpy(user_name, optarg);
+ break;
+ case 'h':
+ default:
+ usage(prog_name, is_root);
+ }
}
- 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]);
+
+ argc -= optind;
+ argv += optind;
+
+ if (!is_root && remote_user_name && !remote_machine) {
+ fprintf(stderr, "%s: You can only use -U with -r.\n", prog_name);
+ usage(prog_name, False);
+ }
+
+ /*
+ * Ensure add_user and either remote machine or join domain are
+ * not both set.
+ */
+
+ if(add_user && ((remote_machine != NULL) || joining_domain))
+ usage(prog_name, True);
+
+ /*
+ * Deal with joining a domain.
+ */
+ if(joining_domain && argc != 0)
+ usage(prog_name, True);
+
+ if(joining_domain) {
+ return join_domain( new_domain, remote_machine);
+ }
+
+ if(is_root) {
+
+ /*
+ * Deal with root - can add a user, but only locally.
+ */
+
+ switch(argc) {
+ case 0:
+ break;
+ case 1:
+ /* If we are root we can change another's password. */
+ pstrcpy(user_name, argv[0]);
+ break;
+ case 2:
+ pstrcpy(user_name, argv[0]);
+ fstrcpy(new_passwd, argv[1]);
+ got_new_pass = True;
+ break;
+ default:
+ usage(prog_name, True);
+ }
+
+ if(*user_name) {
+
+ if(trust_account) {
+ int username_len = strlen(user_name);
+ if(username_len >= sizeof(pstring) - 1) {
+ fprintf(stderr, "%s: machine account name too long.\n", user_name);
+ exit(1);
+ }
+
+ if(user_name[username_len-1] != '$') {
+ user_name[username_len] = '$';
+ user_name[username_len+1] = '\0';
+ }
+ }
+
+ if(!remote_machine && ((pwd = Get_Pwnam(user_name, True)) == NULL)) {
+ fprintf(stderr, "%s: User \"%s\" was not found in system password file.\n",
+ prog_name, user_name);
+ exit(1);
+ }
+ } else {
+ if((pwd = getpwuid(real_uid)) != NULL)
+ pstrcpy( user_name, pwd->pw_name);
+ }
+
+ } else {
+
+ if(add_user) {
+ fprintf(stderr, "%s: Only root can add a user.\n", prog_name);
+ usage(prog_name, False);
+ }
+
+ if(disable_user) {
+ fprintf(stderr, "%s: Only root can disable a user.\n", prog_name);
+ usage(prog_name, False);
+ }
+
+ if(enable_user) {
+ fprintf(stderr, "%s: Only root can enable a user.\n", prog_name);
+ usage(prog_name, False);
+ }
+
+ if(argc > 1)
+ usage(prog_name, False);
+
+ if(argc == 1) {
+ fstrcpy(new_passwd, argv[0]);
+ got_new_pass = True;
+ }
+
+ if(!remote_user_name && ((pwd = getpwuid(real_uid)) != NULL))
+ pstrcpy( user_name, pwd->pw_name);
+
+ /*
+ * A non-root user is always setting a password
+ * via a remote machine (even if that machine is
+ * localhost).
+ */
+
+ if(remote_machine == NULL)
+ remote_machine = "127.0.0.1";
+ }
+
+ if (*user_name == '\0') {
+ fprintf(stderr, "%s: Unable to get a user name for password change.\n", prog_name);
exit(1);
}
+
+ /*
+ * If we are adding a machine account then pretend
+ * we already have the new password, we will be using
+ * the machinename as the password.
+ */
+
+ if(add_user && trust_account) {
+ got_new_pass = True;
+ strncpy(new_passwd, user_name, sizeof(fstring));
+ new_passwd[sizeof(fstring)-1] = '\0';
+ strlower(new_passwd);
+ if(new_passwd[strlen(new_passwd)-1] == '$')
+ new_passwd[strlen(new_passwd)-1] = '\0';
+ }
+
+ /*
+ * If we are root we don't ask for the old password (unless it's on a
+ * remote machine.
+ */
+
+ if (remote_machine != NULL) {
+ p = getpass("Old SMB password:");
+ fstrcpy(old_passwd, p);
+ }
+
+ if (!got_new_pass)
+ prompt_for_new_password(new_passwd);
if (new_passwd[0] == '\0') {
printf("Password not set\n");
exit(0);
}
+
+ /*
+ * Now do things differently depending on if we're changing the
+ * password on a remote machine. Remember - a normal user is
+ * always using this code, looping back to the local smbd.
+ */
+
+ if(remote_machine != NULL) {
+ struct cli_state cli;
+ struct in_addr ip;
+
+ if(!resolve_name( remote_machine, &ip)) {
+ fprintf(stderr, "%s: unable to find an IP address for machine %s.\n",
+ prog_name, remote_machine );
+ exit(1);
+ }
+
+ ZERO_STRUCT(cli);
+
+ if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
+ fprintf(stderr, "%s: unable to connect to SMB server on machine %s. Error was : %s.\n",
+ prog_name, remote_machine, cli_errstr(&cli) );
+ exit(1);
+ }
- /* 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);
+ make_nmb_name(&calling, global_myname , 0x0 , scope);
+ make_nmb_name(&called , remote_machine, 0x20, scope);
+
+ if (!cli_session_request(&cli, &calling, &called))
+ {
+ fprintf(stderr, "%s: machine %s rejected the session setup. Error was : %s.\n",
+ prog_name, remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ exit(1);
+ }
- /* Mangle the passwords into Lanman format */
- old_passwd[14] = '\0';
- strupper(old_passwd);
- new_passwd[14] = '\0';
- strupper(new_passwd);
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ fprintf(stderr, "%s: machine %s rejected the negotiate protocol. Error was : %s.\n",
+ prog_name, remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ exit(1);
+ }
+ if (!cli_session_setup(&cli, user_name, old_passwd, strlen(old_passwd),
+ "", 0, "")) {
+ fprintf(stderr, "%s: machine %s rejected the session setup. Error was : %s.\n",
+ prog_name, remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ exit(1);
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ fprintf(stderr, "%s: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
+ prog_name, remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ exit(1);
+ }
+
+ if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
+ fprintf(stderr, "%s: machine %s rejected the password change: Error was : %s.\n",
+ prog_name, remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ exit(1);
+ }
+
+ cli_shutdown(&cli);
+ exit(0);
+ }
+
/*
- * Calculate the SMB (lanman) hash functions of both old and new passwords.
+ * Check for a machine account.
*/
+
+ if(trust_account && !pwd) {
+ fprintf(stderr, "%s: User %s does not exist in system password file \
+(usually /etc/passwd). Cannot add machine account without a valid system user.\n",
+ prog_name, user_name);
+ exit(1);
+ }
+
+ /* Calculate the MD4 hash (NT compatible) of the new password. */
- memset(old_p16, '\0', 16);
- E_P16((uchar *) old_passwd, old_p16);
-
- memset(new_p16, '\0', 16);
- E_P16((uchar *) new_passwd, new_p16);
-
+ create_new_hashes( new_passwd, new_p16, new_nt_p16);
+
/*
- * Open the smbpaswd file XXXX - we need to parse smb.conf to get the
- * filename
+ * Open the smbpaswd file.
*/
- 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);
+ vp = startsmbpwent(True);
+ if (!vp && errno == ENOENT) {
+ fprintf(stderr,"%s: smbpasswd file did not exist - attempting to create it.\n", prog_name);
+ fp = fopen(lp_smb_passwd_file(), "w");
+ if (fp) {
+ fprintf(fp, "# Samba SMB password file\n");
+ fclose(fp);
+ vp = startsmbpwent(True);
+ }
}
- /* 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);
+ if (!vp) {
+ err = errno;
+ fprintf(stderr, "%s: Failed to open password file %s.\n",
+ prog_name, lp_smb_passwd_file());
+ errno = err;
+ perror(prog_name);
+ 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);
+ smb_pwent = getsmbpwnam(user_name);
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);
+ if(add_user == False) {
+ fprintf(stderr, "%s: Failed to find entry for user %s.\n",
+ prog_name, pwd->pw_name);
+ endsmbpwent(vp);
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);
+
+ /* Create a new smb passwd entry and set it to the given password. */
+ {
+ struct smb_passwd new_smb_pwent;
+
+ new_smb_pwent.smb_userid = pwd->pw_uid;
+ new_smb_pwent.smb_name = pwd->pw_name;
+ new_smb_pwent.smb_passwd = NULL;
+ new_smb_pwent.smb_nt_passwd = NULL;
+ new_smb_pwent.acct_ctrl = (trust_account ? ACB_WSTRUST : ACB_NORMAL);
+
+ if(disable_user) {
+ new_smb_pwent.acct_ctrl |= ACB_DISABLED;
+ } else if (set_no_password) {
+ new_smb_pwent.acct_ctrl |= ACB_PWNOTREQ;
+ } else {
+ new_smb_pwent.smb_passwd = new_p16;
+ new_smb_pwent.smb_nt_passwd = new_nt_p16;
+ }
+
+ if(add_smbpwd_entry(&new_smb_pwent) == False) {
+ fprintf(stderr, "%s: Failed to add entry for user %s.\n",
+ prog_name, pwd->pw_name);
+ endsmbpwent(vp);
+ exit(1);
}
+
+ endsmbpwent(vp);
+ printf("%s: Added user %s.\n", prog_name, user_name);
+ exit(0);
}
+ } else {
+ /* the entry already existed */
+ add_user = False;
}
+
/*
- * If we get here either we were root or the old password checked out
- * ok.
+ * We are root - just write the new password
+ * and the valid last change time.
*/
- /* 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]);
+
+ if(disable_user)
+ smb_pwent->acct_ctrl |= ACB_DISABLED;
+ else if (enable_user) {
+ if(smb_pwent->smb_passwd == NULL) {
+ prompt_for_new_password(new_passwd);
+ create_new_hashes( new_passwd, new_p16, new_nt_p16);
+ smb_pwent->smb_passwd = new_p16;
+ smb_pwent->smb_nt_passwd = new_nt_p16;
}
+ smb_pwent->acct_ctrl &= ~ACB_DISABLED;
+ } else if (set_no_password) {
+ smb_pwent->acct_ctrl |= ACB_PWNOTREQ;
+ /* This is needed to preserve ACB_PWNOTREQ in mod_smbfilepwd_entry */
+ smb_pwent->smb_passwd = NULL;
+ smb_pwent->smb_nt_passwd = NULL;
+ } else {
+ smb_pwent->acct_ctrl &= ~ACB_PWNOTREQ;
+ smb_pwent->smb_passwd = new_p16;
+ smb_pwent->smb_nt_passwd = new_nt_p16;
}
- /*
- * 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);
+
+ if(mod_smbpwd_entry(smb_pwent,True) == False) {
+ fprintf(stderr, "%s: Failed to modify entry for user %s.\n",
+ prog_name, pwd->pw_name);
+ endsmbpwent(vp);
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;
-}
-
-#else
-#include "includes.h"
-
-int
-main(int argc, char **argv)
-{
- printf("smb password encryption not selected in Makefile\n");
+ endsmbpwent(vp);
+ if(disable_user)
+ printf("User %s disabled.\n", user_name);
+ else if(enable_user)
+ printf("User %s enabled.\n", user_name);
+ else if (set_no_password)
+ printf("User %s - set to no password.\n", user_name);
+ else
+ printf("Password changed for user %s.\n", user_name);
return 0;
}
-#endif
diff --git a/source/smbd/smbrun.c b/source/utils/smbrun.c
index df12ae1f85c..2a94ac32353 100644
--- a/source/smbd/smbrun.c
+++ b/source/utils/smbrun.c
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
external program running routine
- 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
@@ -41,56 +41,52 @@ static void close_fds(void)
/*
-This is a wrapper around the system call to allow commands to run correctly
+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[])
+It takes 3 arguments as uid,gid,command and runs command after
+becoming a non-root user */
+ int main(int argc,char *argv[])
{
+ int uid,gid;
+
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);
+ if (argc != 4) exit(2);
+
+ uid = atoi(argv[1]);
+ gid = atoi(argv[2]);
+
+ /* first become root - we may need to do this in order to lose
+ our privilages! */
+#ifdef HAVE_SETRESUID
+ setresgid(0,0,0);
+ setresuid(0,0,0);
#else
- setuid(0);
- seteuid(0);
- setgid(gid);
- setegid(gid);
- setuid(uid);
- seteuid(uid);
+ setuid(0);
+ seteuid(0);
#endif
- if (getuid() != uid)
- return(3);
- }
+#ifdef HAVE_SETRESUID
+ setresgid(gid,gid,gid);
+ setresuid(uid,uid,uid);
+#else
+ setgid(gid);
+ setegid(gid);
+ setuid(uid);
+ seteuid(uid);
+#endif
- if (geteuid() != getuid())
- return(1);
- if (argc < 2)
- return(2);
+ /* paranoia :-) */
+ if (getuid() != uid)
+ return(3);
+
+ if (geteuid() != getuid())
+ return(4);
/* this is to make sure that the system() call doesn't run forever */
alarm(30);
- return(system(argv[1]));
+ return(system(argv[3]));
}
diff --git a/source/utils/status.c b/source/utils/status.c
index ed0ae532114..344d46a9b98 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,81 +17,186 @@
You should have received a copy of the 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;
+
+struct session_record{
+ int pid;
+ int uid;
+ char machine[31];
+ time_t start;
+ struct session_record *next;
+} *srecs;
+
extern int DEBUGLEVEL;
extern FILE *dbf;
+extern pstring myhostname;
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[])
+int shares_only = 0; /* Added by RJS */
+int locks_only = 0; /* Added by RJS */
+
+/* we need these because we link to locking*.o */
+ void become_root(BOOL save_dir) {}
+ void unbecome_root(BOOL restore_dir) {}
+
+
+/* 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 void Ucrit_addPid(int pid)
+{
+ int i;
+ if ( !Ucrit_IsActive) return;
+ for (i=0;i<Ucrit_MaxPid;i++)
+ if( pid == Ucrit_pid[i] ) return;
+ Ucrit_pid[Ucrit_MaxPid++] = pid;
+}
+
+static unsigned int Ucrit_checkPid(int pid)
+{
+ 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) {
+ printf("Locked files:\n");
+ printf("Pid DenyMode R/W Oplock Name\n");
+ printf("--------------------------------------------------\n");
+ }
+ count++;
+
+ if (Ucrit_checkPid(e->pid)) {
+ printf("%-5d ",e->pid);
+ switch ((e->share_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 (e->share_mode&0xF) {
+ case 0: printf("RDONLY "); break;
+ case 1: printf("WRONLY "); break;
+ case 2: printf("RDWR "); break;
+ }
+
+ if((e->op_type &
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ printf("EXCLUSIVE+BATCH ");
+ else if (e->op_type & EXCLUSIVE_OPLOCK)
+ printf("EXCLUSIVE ");
+ else if (e->op_type & BATCH_OPLOCK)
+ printf("BATCH ");
+ else
+ printf("NONE ");
+
+ printf(" %s %s",fname,asctime(LocalTime((time_t *)&e->time.tv_sec)));
+ }
+}
+
+
+
+ int main(int argc, char *argv[])
{
FILE *f;
pstring fname;
- int uid, c, n;
+ int c;
static pstring servicesf = CONFIGFILE;
extern char *optarg;
- int verbose = 0;
- void *dir;
- char *s;
- BOOL firstopen=True;
+ int verbose = 0, brief =0;
BOOL processes_only=False;
int last_pid=0;
+ struct session_record *ptr;
+
+ TimeInit();
setup_logging(argv[0],True);
charset_initialise();
DEBUGLEVEL = 0;
- dbf = fopen("/dev/null","w");
+ dbf = stderr;
if (getuid() != geteuid()) {
printf("smbstatus should not be run setuid\n");
return(1);
}
- while ((c = getopt(argc, argv, "pdsu:")) != EOF) {
+ while ((c = getopt(argc, argv, "pdLSs:u:b")) != EOF) {
switch (c) {
+ case 'b':
+ brief = 1;
+ break;
case 'd':
verbose = 1;
break;
+ case 'L':
+ locks_only = 1;
+ break;
case 'p':
processes_only = 1;
break;
+ case 'S':
+ shares_only = 1;
+ break;
case 's':
- strcpy(servicesf, optarg);
+ pstrcpy(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 */
+ fprintf(stderr, "Usage: %s [-d] [-L] [-p] [-S] [-s configfile] [-u username]\n", *argv); /* changed by OH */
return (-1);
}
}
+ get_myname(myhostname, NULL);
-
- if (!lp_load(servicesf,False)) {
+ if (!lp_load(servicesf,False,False,False)) {
fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
return (-1);
}
@@ -101,10 +206,10 @@ int main(int argc, char *argv[])
printf("lockdir = %s\n", *lp_lockdir() ? lp_lockdir() : "NULL");
}
- strcpy(fname,lp_lockdir());
+ pstrcpy(fname,lp_lockdir());
standard_sub_basic(fname);
trim_string(fname,"","/");
- strcat(fname,"/STATUS..LCK");
+ pstrcat(fname,"/STATUS..LCK");
f = fopen(fname,"r");
if (!f) {
@@ -113,146 +218,110 @@ int main(int argc, char *argv[])
printf("You need to have status=yes in your smb config file\n");
return(0);
}
+ else if (verbose) {
+ printf("Opened status file %s\n", fname);
+ }
- uid = getuid();
+ if (!locks_only) {
- if (!processes_only) {
- printf("\nSamba version %s\n",VERSION);
+ 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 */
+ if (brief)
+ {
+ printf("PID Username Machine Time logged in\n");
+ printf("-------------------------------------------------------------------\n");
+ }
+ else
+ {
+ printf("Service uid gid pid machine\n");
+ printf("----------------------------------------------\n");
}
- 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);
+ while (!feof(f))
+ {
+ if (fread(&crec,sizeof(crec),1,f) != 1)
+ break;
+ if (crec.cnum == -1) continue;
+ if ( crec.magic == 0x280267 && process_exists(crec.pid)
+ && Ucrit_checkUsername(uidtoname(crec.uid)) /* added by OH */
+ )
+ {
+ if (brief)
+ {
+ ptr=srecs;
+ while (ptr!=NULL)
+ {
+ if ((ptr->pid==crec.pid)&&(strncmp(ptr->machine,crec.machine,30)==0))
+ {
+ if (ptr->start > crec.start)
+ ptr->start=crec.start;
+ break;
+ }
+ ptr=ptr->next;
+ }
+ if (ptr==NULL)
+ {
+ ptr=(struct session_record *) malloc(sizeof(struct session_record));
+ ptr->uid=crec.uid;
+ ptr->pid=crec.pid;
+ ptr->start=crec.start;
+ strncpy(ptr->machine,crec.machine,30);
+ ptr->machine[30]='\0';
+ ptr->next=srecs;
+ srecs=ptr;
+ }
+ }
+ else
+ {
+ 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 */
+ }
+ 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)));
+ }
+ }
+ }
+ fclose(f);
+ }
if (processes_only) exit(0);
+
+ if (brief)
+ {
+ ptr=srecs;
+ while (ptr!=NULL)
+ {
+ printf("%-8d%-10.10s%-30.30s%s",ptr->pid,uidtoname(ptr->uid),ptr->machine,asctime(LocalTime(&(ptr->start))));
+ ptr=ptr->next;
+ }
+ printf("\n");
+ 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;
- }
+ if (!shares_only) {
- fname[sizeof(fname)-1] = 0;
+ locking_init(1);
- if (firstopen) {
- firstopen=False;
- printf("Locked files:\n");
- printf("Pid DenyMode R/W Name\n");
- printf("------------------------------\n");
- }
+ if (share_mode_forall(print_share_mode) <= 0)
+ printf("No locked files\n");
+
+ printf("\n");
+ share_status(stdout);
- 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)));
+ locking_end();
}
- closedir(dir);
-
- if (firstopen)
- printf("No locked files\n");
return (0);
}
-/* added by OH */
-void Ucrit_addUsername(pstring username)
-{
- strcpy(Ucrit_username, username);
- if(strlen(Ucrit_username) > 0)
- Ucrit_IsActive = 1;
-}
-
-unsigned int Ucrit_checkUsername(pstring username)
-{
- if ( !Ucrit_IsActive) return 1;
- if (strcmp(Ucrit_username,username) ==0) return 1;
- return 0;
-}
-
-void Ucrit_addPid(int pid)
-{
- int i;
- if ( !Ucrit_IsActive) return;
- for (i=0;i<Ucrit_MaxPid;i++)
- if( pid == Ucrit_pid[i] ) return;
- Ucrit_pid[Ucrit_MaxPid++] = pid;
-}
-
-unsigned int Ucrit_checkPid(int pid)
-{
- int i;
- if ( !Ucrit_IsActive) return 1;
- for (i=0;i<Ucrit_MaxPid;i++)
- if( pid == Ucrit_pid[i] ) return 1;
- return 0;
-}
-
diff --git a/source/utils/testparm.c b/source/utils/testparm.c
index e1f070a4b83..6697dc7fd9d 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,33 +34,66 @@
#include "includes.h"
#include "smb.h"
-#include "params.h"
-#include "loadparm.h"
/* these live in util.c */
extern FILE *dbf;
extern int DEBUGLEVEL;
+extern pstring myhostname;
-int main(int argc, char *argv[])
+/***********************************************
+ Here we do a set of 'hard coded' checks for bad
+ configuration settings.
+************************************************/
+static void do_global_checks(void)
+{
+ SMB_STRUCT_STAT st;
+ if (lp_security() > SEC_SHARE && lp_revalidate(-1)) {
+ printf("WARNING: the 'revalidate' parameter is ignored in all but \
+'security=share' mode.\n");
+ }
+
+ if (lp_wins_support() && *lp_wins_server()) {
+ 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");
+ }
+
+ if (!directory_exist(lp_lockdir(), &st)) {
+ printf("ERROR: lock directory %s does not exist\n",
+ lp_lockdir());
+ } else if ((st.st_mode & 0777) != 0755) {
+ printf("WARNING: lock directory %s should have permissions 0755 for browsing to work\n",
+ lp_lockdir());
+ }
+}
+
+ int main(int argc, char *argv[])
{
pstring configfile;
int s;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
if (argc < 2)
- strcpy(configfile,CONFIGFILE);
+ pstrcpy(configfile,CONFIGFILE);
else
- strcpy(configfile,argv[1]);
+ pstrcpy(configfile,argv[1]);
dbf = stdout;
DEBUGLEVEL = 2;
printf("Load smb config files from %s\n",configfile);
- if (!lp_load(configfile,False))
+ if(!get_myname(myhostname,NULL))
+ {
+ printf("Failed to get my hostname.\n");
+ return(1);
+ }
+
+ if (!lp_load(configfile,False,True,False))
{
printf("Error loading services.\n");
return(1);
@@ -69,6 +102,8 @@ int main(int argc, char *argv[])
printf("Loaded services file OK.\n");
+ do_global_checks();
+
for (s=0;s<1000;s++)
if (VALID_SNUM(s))
if (strlen(lp_servicename(s)) > 8) {
@@ -82,28 +117,27 @@ int main(int argc, char *argv[])
printf("Press enter to see a dump of your service definitions\n");
fflush(stdout);
getc(stdin);
- lp_dump();
+ lp_dump(stdout,True);
}
if (argc == 4)
{
- struct from_host f;
- f.name = argv[2];
- f.addr = argv[3];
+ char *cname = argv[2];
+ char *caddr = argv[3];
/* 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))
+ if (allow_access(lp_hostsdeny(s),lp_hostsallow(s),cname,caddr))
{
printf("Allow connection from %s (%s) to %s\n",
- f.name,f.addr,lp_servicename(s));
+ cname,caddr,lp_servicename(s));
}
else
{
printf("Deny connection from %s (%s) to %s\n",
- f.name,f.addr,lp_servicename(s));
+ cname,caddr,lp_servicename(s));
}
}
}
diff --git a/source/utils/testprns.c b/source/utils/testprns.c
index 89c615898d7..caa9e2740a0 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,7 +33,6 @@
#include "includes.h"
#include "smb.h"
-#include "pcap.h"
/* these live in util.c */
extern FILE *dbf;
@@ -43,6 +42,8 @@ int main(int argc, char *argv[])
{
char *pszTemp;
+ TimeInit();
+
setup_logging(argv[0],True);
charset_initialise();
@@ -52,10 +53,9 @@ int main(int argc, char *argv[])
else
{
dbf = fopen("test.log", "w");
- if (dbf == NULL)
+ 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",
diff --git a/source/utils/torture.c b/source/utils/torture.c
new file mode 100644
index 00000000000..3e29c5a00ab
--- /dev/null
+++ b/source/utils/torture.c
@@ -0,0 +1,986 @@
+/*
+ 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="";
+
+
+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);
+}
+
+
+static BOOL open_connection(struct cli_state *c)
+{
+ if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
+ printf("Failed to connect with %s\n", host);
+ return False;
+ }
+
+ if (!cli_session_request(c, host, 0x20, myname)) {
+ printf("%s rejected the session\n",host);
+ cli_shutdown(c);
+ return False;
+ }
+
+ c->protocol = max_protocol;
+
+ 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),
+ "", 0, workgroup)) {
+ printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ if (!cli_send_tconX(c, share,
+ strstr(share,"IPC$")?"IPC":"A:",
+ password, strlen(password)+1)) {
+ printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
+ cli_shutdown(c);
+ return False;
+ }
+
+ return True;
+}
+
+
+
+static void close_connection(struct cli_state *c)
+{
+ if (!cli_tdis(c)) {
+ printf("tdis failed (%s)\n", cli_errstr(c));
+ }
+
+ cli_shutdown(c);
+}
+
+
+static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
+{
+ while (!cli_lock(c, fnum, offset, len, -1)) {
+ int eclass, num;
+ cli_error(c, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("lock failed (%s)\n",
+ cli_errstr(c));
+ return False;
+ }
+ }
+ return True;
+}
+
+
+static BOOL rw_torture(struct cli_state *c, int numops)
+{
+ char *lockfname = "\\torture.lck";
+ fstring fname;
+ int fnum;
+ int fnum2;
+ int pid2, pid = getpid();
+ int i, j;
+ char buf[1024];
+
+ 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));
+ break;
+ }
+
+ if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ }
+
+ for (j=0;j<50;j++) {
+ if (cli_write(c, fnum, (char *)buf,
+ sizeof(pid)+(j*sizeof(buf)),
+ sizeof(buf)) != sizeof(buf)) {
+ printf("write failed (%s)\n", cli_errstr(c));
+ }
+ }
+
+ pid2 = 0;
+
+ if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ printf("read failed (%s)\n", cli_errstr(c));
+ }
+
+ if (pid2 != pid) {
+ printf("data corruption!\n");
+ }
+
+ if (!cli_close(c, fnum)) {
+ printf("close failed (%s)\n", cli_errstr(c));
+ }
+
+ if (!cli_unlink(c, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(c));
+ }
+
+ if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
+ printf("unlock failed (%s)\n", cli_errstr(c));
+ }
+ }
+
+ cli_close(c, fnum2);
+ cli_unlink(c, lockfname);
+
+ printf("%d\n", i);
+
+ return True;
+}
+
+static void usage(void)
+{
+ printf("Usage: smbtorture //server/share <options>\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("\n");
+
+ exit(1);
+}
+
+
+
+static void run_torture(int numops)
+{
+ static struct cli_state cli;
+
+ if (open_connection(&cli)) {
+ cli_sockopt(&cli, sockops);
+
+ printf("pid %d OK\n", getpid());
+
+ rw_torture(&cli, numops);
+
+ close_connection(&cli);
+ }
+}
+
+/*
+ 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 void run_locktest1(void)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt1.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
+
+ if (!open_connection(&cli1) || !open_connection(&cli2)) {
+ return;
+ }
+ 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;
+ }
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+ fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum3 == -1) {
+ printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+
+ printf("Testing lock timeouts\n");
+ t1 = time(NULL);
+ if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+ 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;
+ }
+
+ if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
+ printf("lock4 succeeded! This is a locking bug\n");
+ return;
+ } else {
+ int eclass, num;
+ cli_error(&cli2, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli2));
+ return;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_close(&cli2, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli2));
+ return;
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+
+ close_connection(&cli1);
+ close_connection(&cli2);
+
+ printf("Passed locktest1\n");
+}
+
+
+/*
+ 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 void run_locktest2(void)
+{
+ static struct cli_state cli;
+ char *fname = "\\lockt2.lck";
+ int fnum1, fnum2, fnum3;
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ 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;
+ }
+
+ fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
+ return;
+ }
+
+ 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;
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
+ printf("lock1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (cli_lock(&cli, fnum2, 0, 4, 0)) {
+ printf("lock2 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 2);
+
+ if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
+ printf("unlock1 succeeded! This is a locking bug\n");
+ }
+
+ if (cli_lock(&cli, fnum3, 0, 4, 0)) {
+ printf("lock3 succeeded! This is a locking bug\n");
+ } else {
+ int eclass, num;
+ cli_error(&cli, &eclass, &num);
+ if (eclass != ERRDOS || num != ERRlock) {
+ printf("error should have been ERRDOS/ERRlock (%s)\n",
+ cli_errstr(&cli));
+ return;
+ }
+ }
+
+ cli_setpid(&cli, 1);
+
+ if (!cli_close(&cli, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ if (!cli_close(&cli, fnum3)) {
+ printf("close3 failed (%s)\n", cli_errstr(&cli));
+ return;
+ }
+
+ close_connection(&cli);
+
+ printf("locktest2 finished\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports the full offset range in lock requests
+*/
+static void run_locktest3(int numops)
+{
+ static struct cli_state cli1, cli2;
+ char *fname = "\\lockt3.lck";
+ int fnum1, fnum2, i;
+ uint32 offset;
+
+#define NEXT_OFFSET offset += (~(uint32)0) / numops
+
+ if (!open_connection(&cli1) || !open_connection(&cli2)) {
+ return;
+ }
+ 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;
+ }
+ fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
+ return;
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+ if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+ printf("lock1 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+ printf("lock2 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+
+ if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
+ printf("error: lock1 %d succeeded!\n", i);
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
+ printf("error: lock2 %d succeeded!\n", i);
+ return;
+ }
+
+ if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
+ printf("error: lock3 %d succeeded!\n", i);
+ return;
+ }
+
+ if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
+ printf("error: lock4 %d succeeded!\n", i);
+ return;
+ }
+ }
+
+ for (offset=i=0;i<numops;i++) {
+ NEXT_OFFSET;
+
+ if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
+ printf("unlock1 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
+ printf("unlock2 %d failed (%s)\n",
+ i,
+ cli_errstr(&cli1));
+ return;
+ }
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close1 failed (%s)\n", cli_errstr(&cli1));
+ }
+
+ if (!cli_close(&cli2, fnum2)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli2));
+ }
+
+ if (!cli_unlink(&cli1, fname)) {
+ printf("unlink failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ close_connection(&cli1);
+ close_connection(&cli2);
+
+ printf("finished locktest3\n");
+}
+
+
+/*
+ This test checks that
+
+ 1) the server does not allow an unlink on a file that is open
+*/
+static void run_unlinktest(void)
+{
+ static struct cli_state cli;
+ char *fname = "\\unlink.tst";
+ int fnum;
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ 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;
+ }
+
+ if (cli_unlink(&cli, fname)) {
+ printf("error: server allowed unlink on an open file\n");
+ }
+
+ cli_close(&cli, fnum);
+ cli_unlink(&cli, fname);
+
+ close_connection(&cli);
+
+ printf("unlink test finished\n");
+}
+
+/* generate a random buffer */
+static void rand_buf(char *buf, int len)
+{
+ while (len--) {
+ *buf = sys_random();
+ buf++;
+ }
+}
+
+/* send random IPC commands */
+static void run_randomipc(void)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ pstring param;
+ int api, param_len, i;
+ static struct cli_state cli;
+ struct {
+ int api, level;
+ char *format;
+ char *subformat;
+ int len;
+ } foo;
+
+ printf("starting random ipc test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ for (i=0;i<1000;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);
+ }
+
+ close_connection(&cli);
+
+ printf("finished random ipc test\n");
+}
+
+
+
+static void browse_callback(char *sname, uint32 stype, char *comment)
+{
+ printf("\t%20.20s %08x %s\n", sname, stype, comment);
+}
+
+
+
+/*
+ This test checks the browse list code
+
+*/
+static void run_browsetest(void)
+{
+ static struct cli_state cli;
+
+ printf("starting browse test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ printf("domain list:\n");
+ cli_NetServerEnum(&cli, workgroup,
+ SV_TYPE_DOMAIN_ENUM,
+ browse_callback);
+
+ printf("machine list:\n");
+ cli_NetServerEnum(&cli, workgroup,
+ SV_TYPE_ALL,
+ browse_callback);
+
+ close_connection(&cli);
+
+ printf("browse test finished\n");
+}
+
+
+/*
+ This checks how the getatr calls works
+*/
+static void run_attrtest(void)
+{
+ static struct cli_state cli;
+ int fnum;
+ time_t t, t2;
+ char *fname = "\\attrib.tst";
+
+ printf("starting attrib test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ 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));
+ }
+
+ if (abs(t - time(NULL)) > 2) {
+ printf("ERROR: SMBgetatr bug. time is %s",
+ ctime(&t));
+ t = time(NULL);
+ }
+
+ t2 = t-60*60*24; /* 1 day ago */
+
+ if (!cli_setatr(&cli, fname, 0, t2)) {
+ printf("setatr failed (%s)\n", cli_errstr(&cli));
+ }
+
+ if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
+ printf("getatr failed (%s)\n", cli_errstr(&cli));
+ }
+
+ if (t != t2) {
+ printf("ERROR: getatr/setatr bug. times are\n%s",
+ ctime(&t));
+ printf("%s", ctime(&t2));
+ }
+
+ cli_unlink(&cli, fname);
+
+ close_connection(&cli);
+
+ printf("attrib test finished\n");
+}
+
+
+/*
+ This checks a couple of trans2 calls
+*/
+static void run_trans2test(void)
+{
+ static struct cli_state cli;
+ int fnum;
+ uint32 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";
+
+ printf("starting trans2 test\n");
+
+ if (!open_connection(&cli)) {
+ return;
+ }
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (!cli_qfileinfo(&cli, fnum, &c_time, &a_time, &m_time, &size)) {
+ printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
+ }
+ cli_close(&cli, fnum);
+
+ sleep(2);
+
+ cli_unlink(&cli, fname);
+ fnum = cli_open(&cli, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_close(&cli, fnum);
+
+ if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size)) {
+ printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
+ } 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");
+ }
+ if (a_time % (60*60) == 0) {
+ printf("access time=%s", ctime(&a_time));
+ printf("This system appears to set a midnight access time\n");
+ }
+
+ if (abs(m_time - time(NULL)) > 60*60*24*7) {
+ printf("ERROR: totally incorrect times - maybe word reversed?\n");
+ }
+ }
+
+
+ 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)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ } 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");
+ }
+ }
+
+ 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));
+ }
+ sleep(3);
+ if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
+ &w_time, &size)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ }
+
+ fnum = cli_open(&cli, fname2,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ cli_write(&cli, fnum, (char *)&fnum, 0, sizeof(fnum));
+ cli_close(&cli, fnum);
+ if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
+ &w_time, &size)) {
+ printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
+ } else {
+ if (m_time2 == m_time)
+ printf("This system does not update directory modification times\n");
+ }
+ cli_unlink(&cli, fname2);
+ cli_rmdir(&cli, dname);
+
+
+ close_connection(&cli);
+
+ printf("trans2 test finished\n");
+}
+
+
+static void create_procs(int nprocs, int numops)
+{
+ int i, status;
+
+ for (i=0;i<nprocs;i++) {
+ if (fork() == 0) {
+ int mypid = getpid();
+ sys_srandom(mypid ^ time(NULL));
+ run_torture(numops);
+ _exit(0);
+ }
+ }
+
+ for (i=0;i<nprocs;i++)
+ waitpid(0, &status, 0);
+}
+
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+ int main(int argc,char *argv[])
+{
+ int nprocs=1, numops=100;
+ int opt;
+ char *p;
+ int gotpass = 0;
+ extern char *optarg;
+ extern int optind;
+ extern FILE *dbf;
+
+ dbf = stdout;
+
+ charset_initialise();
+
+ 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(&host[2],'/');
+ if (!p) {
+ usage();
+ }
+ *p = 0;
+ fstrcpy(share, p+1);
+
+ get_myname(myname,NULL);
+
+ if (*username == 0 && getenv("LOGNAME")) {
+ pstrcpy(username,getenv("LOGNAME"));
+ }
+
+ argc--;
+ argv++;
+
+
+ while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != 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 'O':
+ sockops = optarg;
+ break;
+ case 'n':
+ fstrcpy(myname, optarg);
+ break;
+ case 'U':
+ pstrcpy(username,optarg);
+ p = strchr(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);
+
+ run_randomipc();
+
+ start_timer();
+ create_procs(nprocs, numops);
+ printf("rw_torture: %g secs\n", end_timer());
+
+ run_locktest1();
+ run_locktest2();
+ run_locktest3(numops);
+ run_unlinktest();
+ run_browsetest();
+ run_attrtest();
+ run_trans2test();
+
+ 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..bf99a67a048
--- /dev/null
+++ b/source/web/cgi.c
@@ -0,0 +1,526 @@
+/*
+ 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)
+
+#define CGI_LOGGING 0
+
+#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 void unescape(char *buf)
+{
+ char *p=buf;
+
+ while ((p=strchr(p,'+')))
+ *p = ' ';
+
+ p = buf;
+
+ while (p && *p && (p=strchr(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;
+ int i = 0;
+ int len = 1024;
+
+ ret = (char *)malloc(len);
+ if (!ret) return NULL;
+
+
+ while ((*cl)) {
+ int c = fgetc(f);
+ (*cl)--;
+
+ if (c == EOF) {
+ (*cl) = 0;
+ break;
+ }
+
+ if (c == '\r') continue;
+
+ if (strchr("\n&", c)) break;
+
+ ret[i++] = c;
+
+ if (i == len-1) {
+ char *ret2;
+ ret2 = (char *)realloc(ret, len*2);
+ if (!ret2) return ret;
+ len *= 2;
+ ret = ret2;
+ }
+ }
+
+
+ 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(FILE *f1)
+{
+ FILE *f = f1;
+ static char *line;
+ char *p, *s, *tok;
+ int len;
+
+#ifdef DEBUG_COMMENTS
+ char dummy[100]="";
+ print_title(dummy);
+ printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
+#endif
+
+ if (!f1) {
+ f = stdin;
+ if (!content_length) {
+ p = getenv("CONTENT_LENGTH");
+ len = p?atoi(p):0;
+ } else {
+ len = content_length;
+ }
+ } else {
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ }
+
+
+ if (len > 0 &&
+ (f1 || request_post ||
+ ((s=getenv("REQUEST_METHOD")) &&
+ strcasecmp(s,"POST")==0))) {
+ while (len && (line=grab_line(f, &len))) {
+ p = strchr(line,'=');
+ if (!p) continue;
+
+ *p = 0;
+
+ variables[num_variables].name = strdup(line);
+ variables[num_variables].value = strdup(p+1);
+
+ 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;
+ }
+ }
+
+ if (f1) {
+#ifdef DEBUG_COMMENTS
+ printf("<!== End dump in cgi_load_variables() ==>\n");
+#endif
+ return;
+ }
+
+ fclose(stdin);
+
+ if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
+ for (tok=strtok(s,"&;");tok;tok=strtok(NULL,"&;")) {
+ p = strchr(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
+}
+
+
+/***************************************************************************
+ 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)
+{
+ printf("HTTP/1.1 %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", err, header, err, err, info);
+ 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(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 int cgi_handle_authorization(char *line)
+{
+ char *p, *user, *pass;
+
+ if (strncasecmp(line,"Basic ", 6)) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "Only basic authorization is understood");
+ }
+ line += 6;
+ while (line[0] == ' ') line++;
+ base64_decode(line);
+ if (!(p=strchr(line,':'))) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "username/password must be supplied");
+ }
+ *p = 0;
+ user = line;
+ pass = p+1;
+
+ /* currently only allow connections as root */
+ if (strcmp(user,"root")) {
+ cgi_setup_error("401 Bad Authorization", "",
+ "incorrect username/password");
+ }
+
+
+ return pass_check(user, pass, strlen(pass), NULL, NULL);
+}
+
+
+/***************************************************************************
+handle a file download
+ ***************************************************************************/
+static void cgi_download(char *file)
+{
+ SMB_STRUCT_STAT st;
+ char buf[1024];
+ int fd, l, i;
+ char *p;
+
+ /* sanitise the filename */
+ for (i=0;file[i];i++) {
+ if (!isalnum((int)file[i]) && !strchr("/.-_", 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 = open(file,O_RDONLY);
+ if (fd == -1) {
+ cgi_setup_error("404 File Not Found","",
+ "The requested file was not found");
+ }
+ printf("HTTP/1.1 200 OK\r\n");
+ if ((p=strrchr(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 {
+ printf("Content-Type: text/html\r\n");
+ }
+ }
+ printf("Expires: %s\r\n", http_timestring(time(NULL)+EXPIRY_TIME));
+
+ 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);
+}
+
+
+/***************************************************************************
+setup the cgi framework, handling the possability that this program is either
+run as a true cgi program by a web browser or is itself a mini web server
+ ***************************************************************************/
+void cgi_setup(char *rootdir, int auth_required)
+{
+ int authenticated = 0;
+ char line[1024];
+ char *url=NULL;
+ char *p;
+#if CGI_LOGGING
+ FILE *f;
+#endif
+
+ if (chdir(rootdir)) {
+ cgi_setup_error("400 Server Error", "",
+ "chdir failed - the server is not configured correctly");
+ }
+
+ if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
+ /* assume we are running under a real web server */
+ return;
+ }
+
+#if CGI_LOGGING
+ f = fopen("/tmp/cgi.log", "a");
+ if (f) fprintf(f,"\n[Date: %s %s (%s)]\n",
+ http_timestring(time(NULL)),
+ client_name(1), client_addr(1));
+#endif
+
+ /* 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 CGI_LOGGING
+ if (f) fputs(line, f);
+#endif
+ if (line[0] == '\r' || line[0] == '\n') break;
+ if (strncasecmp(line,"GET ", 4)==0) {
+ url = strdup(&line[4]);
+ } else if (strncasecmp(line,"POST ", 5)==0) {
+ request_post = 1;
+ url = strdup(&line[5]);
+ } else if (strncasecmp(line,"PUT ", 4)==0) {
+ 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]);
+ }
+ /* ignore all other requests! */
+ }
+#if CGI_LOGGING
+ if (f) fclose(f);
+#endif
+
+ if (auth_required && !authenticated) {
+ cgi_setup_error("401 Authorization Required",
+ "WWW-Authenticate: Basic realm=\"root\"\r\n",
+ "You must be authenticated to use this service");
+ }
+
+ if (!url) {
+ cgi_setup_error("400 Bad Request", "",
+ "You must specify a GET or POST request");
+ }
+
+ /* trim the URL */
+ if ((p = strchr(url,' ')) || (p=strchr(url,'\t'))) {
+ *p = 0;
+ }
+ while (*url && strchr("\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(url,'?'))) {
+ query_string = p+1;
+ *p = 0;
+ }
+
+ string_sub(url, "/swat/", "");
+
+ if (strstr(url,"..")==0 && file_exist(url, NULL)) {
+ cgi_download(url);
+ }
+
+ printf("HTTP/1.1 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 (baseurl) {
+ return baseurl;
+ }
+ return getenv("SCRIPT_NAME");
+}
+
+/***************************************************************************
+return the current pages path info
+ ***************************************************************************/
+char *cgi_pathinfo(void)
+{
+ char *r;
+ if (pathinfo) {
+ 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 (baseurl) {
+ return client_name(1);
+ }
+ return getenv("REMOTE_HOST");
+}
+
+/***************************************************************************
+return the hostname of the client
+ ***************************************************************************/
+char *cgi_remote_addr(void)
+{
+ if (baseurl) {
+ return client_addr(1);
+ }
+ return getenv("REMOTE_ADDR");
+}
+
+
+/***************************************************************************
+return True if the request was a POST
+ ***************************************************************************/
+BOOL cgi_waspost(void)
+{
+ if (baseurl) {
+ 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..054de2a631d
--- /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"))) != -1) {
+ if ((ip_list = name_query(fd, "__SAMBA__", 0,
+ True, True, loopback_ip,
+ &count,0)) != NULL) {
+ 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/startstop.c b/source/web/startstop.c
new file mode 100644
index 00000000000..9eeac96cc0c
--- /dev/null
+++ b/source/web/startstop.c
@@ -0,0 +1,104 @@
+/*
+ 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"
+
+/* need to wait for daemons to startup */
+#define SLEEP_TIME 3
+
+/* startup smbd */
+void start_smbd(void)
+{
+ pstring binfile;
+
+ if (geteuid() != 0) return;
+
+ if (fork()) {
+ sleep(SLEEP_TIME);
+ return;
+ }
+
+ slprintf(binfile, sizeof(pstring) - 1, "%s/smbd", 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", 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..184f7e1f73c
--- /dev/null
+++ b/source/web/statuspage.c
@@ -0,0 +1,260 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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"
+
+
+static char *tstring(time_t t)
+{
+ static pstring buf;
+ pstrcpy(buf, asctime(LocalTime(&t)));
+ string_sub(buf," ","&nbsp;");
+ return buf;
+}
+
+static void print_share_mode(share_mode_entry *e, char *fname)
+{
+ printf("<tr><td>%d</td>",e->pid);
+ printf("<td>");
+ switch ((e->share_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;
+ }
+ printf("</td>");
+
+ printf("<td>");
+ switch (e->share_mode&0xF) {
+ case 0: printf("RDONLY "); break;
+ case 1: printf("WRONLY "); break;
+ case 2: printf("RDWR "); break;
+ }
+ printf("</td>");
+
+ printf("<td>");
+ if((e->op_type &
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
+ (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ printf("EXCLUSIVE+BATCH ");
+ else if (e->op_type & EXCLUSIVE_OPLOCK)
+ printf("EXCLUSIVE ");
+ else if (e->op_type & BATCH_OPLOCK)
+ printf("BATCH ");
+ else
+ printf("NONE ");
+ printf("</td>");
+
+ printf("<td>%s</td><td>%s</td></tr>\n",
+ fname,tstring(e->time.tv_sec));
+}
+
+
+/* show the current server status */
+void status_page(void)
+{
+ struct connect_record crec;
+ pstring fname;
+ FILE *f;
+ char *v;
+ int autorefresh=0;
+ int refresh_interval=30;
+
+ if (cgi_variable("smbd_restart")) {
+ if (smbd_running())
+ stop_smbd();
+ start_smbd();
+ }
+
+ if (cgi_variable("smbd_start")) {
+ start_smbd();
+ }
+
+ if (cgi_variable("smbd_stop")) {
+ stop_smbd();
+ }
+
+ if (cgi_variable("nmbd_restart")) {
+ if (nmbd_running())
+ 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);
+ }
+
+ pstrcpy(fname,lp_lockdir());
+ standard_sub_basic(fname);
+ trim_string(fname,"","/");
+ pstrcat(fname,"/STATUS..LCK");
+
+
+ f = fopen(fname,"r");
+ if (f) {
+ while (!feof(f)) {
+ if (fread(&crec,sizeof(crec),1,f) != 1) break;
+ if (crec.magic == 0x280267 && crec.cnum == -1 &&
+ process_exists(crec.pid)) {
+ char buf[30];
+ slprintf(buf,sizeof(buf)-1,"kill_%d", crec.pid);
+ if (cgi_variable(buf)) {
+ kill_pid(crec.pid);
+ }
+ }
+ }
+ fclose(f);
+ }
+
+ printf("<H2>Server Status</H2>\n");
+
+ printf("<FORM method=post>\n");
+
+ if (!autorefresh) {
+ printf("<input type=submit value=\"Auto Refresh\" name=autorefresh>\n");
+ printf("<br>Refresh Interval: ");
+ printf("<input type=text size=2 name=\"refresh_interval\" value=%d>\n",
+ refresh_interval);
+ } else {
+ printf("<input type=submit value=\"Stop Refreshing\" name=norefresh>\n");
+ printf("<br>Refresh Interval: %d\n", refresh_interval);
+ printf("<input type=hidden name=refresh value=1>\n");
+ }
+
+ printf("<p>\n");
+
+ 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;
+ }
+
+
+ printf("<table>\n");
+
+ printf("<tr><td>version:</td><td>%s</td></tr>",VERSION);
+
+ fflush(stdout);
+ if (smbd_running()) {
+ printf("<tr><td>smbd:</td><td>running</td><td><input type=submit name=\"smbd_stop\" value=\"Stop smbd\"></td><td><input type=submit name=\"smbd_restart\" value=\"Restart smbd\"></td></tr>\n");
+ } else {
+ printf("<tr><td>smbd:</td><td>not running</td><td><input type=submit name=\"smbd_start\" value=\"Start smbd\"></td>><td><input type=submit name=\"smbd_restart\" value=\"Restart smbd\"></td></tr>\n");
+ }
+
+ fflush(stdout);
+ if (nmbd_running()) {
+ printf("<tr><td>nmbd:</td><td>running</td><td><input type=submit name=\"nmbd_stop\" value=\"Stop nmbd\"></td><td><input type=submit name=\"nmbd_restart\" value=\"Restart nmbd\"></td></tr>\n");
+ } else {
+ printf("<tr><td>nmbd:</td><td>not running</td><td><input type=submit name=\"nmbd_start\" value=\"Start nmbd\"></td><td><input type=submit name=\"nmbd_restart\" value=\"Restart nmbd\"></td></tr>\n");
+ }
+
+ printf("</table>\n");
+ fflush(stdout);
+
+
+ if (geteuid() != 0)
+ printf("<b>NOTE: You are not logged in as root and won't be able to start/stop the server</b><p>\n");
+
+ printf("<p><h3>Active Connections</h3>\n");
+ printf("<table border=1>\n");
+ printf("<tr><th>PID</th><th>Client</th><th>IP address</th><th>Date</th><th>Kill</th></tr>\n");
+
+ while (!feof(f)) {
+ if (fread(&crec,sizeof(crec),1,f) != 1)
+ break;
+ if (crec.magic == 0x280267 &&
+ crec.cnum == -1 &&
+ process_exists(crec.pid)) {
+ printf("<tr><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td><input type=submit value=\"X\" name=\"kill_%d\"></td></tr>\n",
+ crec.pid,
+ crec.machine,crec.addr,
+ tstring(crec.start),
+ crec.pid);
+ }
+ }
+
+ printf("</table><p>\n");
+
+ fseek(f, 0, SEEK_SET);
+
+ printf("<p><h3>Active Shares</h3>\n");
+ printf("<table border=1>\n");
+ printf("<tr><th>Share</th><th>User</th><th>Group</th><th>PID</th><th>Client</th><th>Date</th></tr>\n\n");
+
+ while (!feof(f)) {
+ if (fread(&crec,sizeof(crec),1,f) != 1)
+ break;
+ if (crec.cnum == -1) continue;
+ if (crec.magic == 0x280267 && process_exists(crec.pid)) {
+ 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),crec.pid,
+ crec.machine,
+ tstring(crec.start));
+ }
+ }
+
+ printf("</table><p>\n");
+
+ printf("<h3>Open Files</h3>\n");
+ printf("<table border=1>\n");
+ printf("<tr><th>PID</th><th>Sharing</th><th>R/W</th><th>Oplock</th><th>File</th><th>Date</th></tr>\n");
+
+ locking_init(1);
+ share_mode_forall(print_share_mode);
+ locking_end();
+ printf("</table>\n");
+
+ fclose(f);
+
+ 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 */
+ printf("<script language=\"JavaScript\">\n");
+ printf("<!--\nsetTimeout('window.location.replace(\"%s/status?refresh_interval=%d&refresh=1\")', %d)\n",
+ cgi_baseurl(),
+ refresh_interval,
+ refresh_interval*1000);
+ printf("//-->\n</script>\n");
+ }
+}
+
diff --git a/source/web/swat.c b/source/web/swat.c
new file mode 100644
index 00000000000..7a2f081d266
--- /dev/null
+++ b/source/web/swat.c
@@ -0,0 +1,676 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ 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.
+*/
+
+#ifdef SYSLOG
+#undef SYSLOG
+#endif
+
+#include "includes.h"
+#include "smb.h"
+
+#define GLOBALS_SNUM -1
+
+static pstring servicesf = CONFIGFILE;
+
+
+/* we need these because we link to locking*.o */
+ void become_root(BOOL save_dir) {}
+ void unbecome_root(BOOL restore_dir) {}
+/* We need this because we link to password.o */
+BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override) {return False;}
+
+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;
+
+ *p = '\0';
+ while (*str) {
+ if (*str == '\\') {*p++ = '\\';*p++ = '\\';}
+ else *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)
+{
+ FILE *f = fopen(fname,"r");
+ char buf[1024];
+ int ret;
+
+ if (!f) {
+ printf("ERROR: Can't open %s\n", fname);
+ return 0;
+ }
+
+ while (!feof(f)) {
+ ret = fread(buf, 1, sizeof(buf), f);
+ if (ret <= 0) break;
+ fwrite(buf, 1, ret, stdout);
+ }
+
+ fclose(f);
+ return 1;
+}
+
+/* start the page with standard stuff */
+static void print_header(void)
+{
+ if (!cgi_waspost()) {
+ printf("Expires: 0\r\n");
+ }
+ printf("Content-type: text/html\r\n\r\n");
+
+ if (!include_html("include/header.html")) {
+ printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
+ printf("<HTML>\n<HEAD>\n<TITLE>Samba Web Administration Tool</TITLE>\n</HEAD>\n<BODY background=\"/swat/images/background.jpg\">\n\n");
+ }
+}
+
+
+/* finish off the page */
+static void print_footer(void)
+{
+ if (!include_html("include/footer.html")) {
+ 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><A HREF=\"/swat/help/parameters.html#%s\">?</A> %s</td><td>",
+ parm->label, parm->label);
+
+ switch (parm->type) {
+ case P_CHAR:
+ printf("<input type=text size=2 name=\"parm_%s\" value=\"%c\">",
+ make_parm_name(parm->label), *(char *)ptr);
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%c\'\">",
+ make_parm_name(parm->label),(char)(parm->def.cvalue));
+ break;
+
+ case P_STRING:
+ case P_USTRING:
+ printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
+ make_parm_name(parm->label), *(char **)ptr);
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
+ break;
+
+ case P_GSTRING:
+ case P_UGSTRING:
+ printf("<input type=text size=40 name=\"parm_%s\" value=\"%s\">",
+ make_parm_name(parm->label), (char *)ptr);
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%s\'\">",
+ make_parm_name(parm->label),fix_backslash((char *)(parm->def.svalue)));
+ break;
+
+ case P_BOOL:
+ printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ printf("<option %s>Yes", (*(BOOL *)ptr)?"selected":"");
+ printf("<option %s>No", (*(BOOL *)ptr)?"":"selected");
+ printf("</select>");
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?0:1);
+ break;
+
+ case P_BOOLREV:
+ printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ printf("<option %s>Yes", (*(BOOL *)ptr)?"":"selected");
+ printf("<option %s>No", (*(BOOL *)ptr)?"selected":"");
+ printf("</select>");
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ make_parm_name(parm->label),(BOOL)(parm->def.bvalue)?1:0);
+ break;
+
+ case P_INTEGER:
+ printf("<input type=text size=8 name=\"parm_%s\" value=%d>", make_parm_name(parm->label), *(int *)ptr);
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'%d\'\">",
+ make_parm_name(parm->label),(int)(parm->def.ivalue));
+ break;
+
+ case P_OCTAL:
+ printf("<input type=text size=8 name=\"parm_%s\" value=0%o>", make_parm_name(parm->label), *(int *)ptr);
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.value=\'0%o\'\">",
+ make_parm_name(parm->label),(int)(parm->def.ivalue));
+ break;
+
+ case P_ENUM:
+ printf("<select name=\"parm_%s\">",make_parm_name(parm->label));
+ for (i=0;parm->enum_list[i].name;i++)
+ printf("<option %s>%s",(*(int *)ptr)==parm->enum_list[i].value?"selected":"",parm->enum_list[i].name);
+ printf("</select>");
+ printf("<input type=button value=\"Set Default\" onClick=\"swatform.parm_%s.selectedIndex=\'%d\'\">",
+ make_parm_name(parm->label),enum_index((int)(parm->def.ivalue),parm->enum_list));
+ break;
+ case P_SEP:
+ break;
+ }
+ 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 (!advanced) {
+ if (!printers && !(parm->flags & FLAG_BASIC)) {
+ void *ptr = parm->ptr;
+
+ switch (parm->type) {
+ case P_CHAR:
+ if (*(char *)ptr == (char)(parm->def.cvalue)) 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) {
+ printf("<tr><td></td></tr><tr><td><b><u>%s</u></b></td></tr>\n", heading);
+ last_heading = heading;
+ }
+ show_parameter(snum, parm);
+ }
+}
+
+
+/* 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());
+
+ lp_dump(f, show_defaults);
+}
+
+
+/* save and reoad the smb.conf config file */
+static int save_reload(void)
+{
+ FILE *f;
+
+ f = fopen(servicesf,"w");
+ if (!f) {
+ printf("failed to open %s for writing\n", servicesf);
+ return 0;
+ }
+
+ write_config(f, False);
+ fclose(f);
+
+ lp_killunused(NULL);
+
+ if (!lp_load(servicesf,False,False,False)) {
+ printf("Can't reload %s\n", servicesf);
+ return 0;
+ }
+
+ 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);
+ }
+ }
+}
+
+
+/* load the smb.conf file into loadparm. */
+static void load_config(void)
+{
+ if (!lp_load(servicesf,False,True,False)) {
+ printf("<b>Can't load %s - using defaults</b><p>\n",
+ servicesf);
+ }
+}
+
+/* spit out the html for a link with an image */
+static void image_link(char *name,char *hlink, char *src, int width, int height)
+{
+ printf("<A HREF=\"%s/%s\"><img width=%d height=%d src=\"/swat/%s\" alt=\"%s\"></A>\n",
+ cgi_baseurl(),
+ hlink, width, height,
+ src, name);
+}
+
+/* display the main navigation controls at the top of each page along
+ with a title */
+static void show_main_buttons(void)
+{
+ image_link("Home", "", "images/home.gif", 50, 50);
+ image_link("Globals", "globals", "images/globals.gif", 50, 50);
+ image_link("Shares", "shares", "images/shares.gif", 50, 50);
+ image_link("Printers", "printers", "images/printers.gif", 50, 50);
+ image_link("Status", "status", "images/status.gif", 50, 50);
+ image_link("View Config", "viewconfig", "images/viewconfig.gif", 50, 50);
+
+ 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;
+ }
+
+ printf("<H2>Current Config</H2>\n");
+ printf("<form method=post>\n");
+
+ if (full_view) {
+ printf("<input type=submit name=\"normal_view\" value=\"Normal View\">\n");
+ } else {
+ printf("<input type=submit name=\"full_view\" value=\"Full View\">\n");
+ }
+
+ printf("<p><pre>");
+ write_config(stdout, full_view);
+ printf("</pre>");
+ printf("</form>\n");
+}
+
+
+/* display a globals editing page */
+static void globals_page(void)
+{
+ int advanced = 0;
+
+ printf("<H2>Global Variables</H2>\n");
+
+ if (cgi_variable("Advanced") && !cgi_variable("Basic"))
+ advanced = 1;
+
+ if (cgi_variable("Commit")) {
+ commit_parameters(GLOBALS_SNUM);
+ save_reload();
+ }
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
+ printf("<input type=reset name=\"Reset Values\" value=\"Reset Values\">\n");
+ if (advanced == 0) {
+ printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
+ } else {
+ printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
+ }
+ printf("<p>\n");
+
+ printf("<table>\n");
+ show_parameters(GLOBALS_SNUM, 1, advanced, 0);
+ printf("</table>\n");
+
+ if (advanced) {
+ printf("<input type=hidden name=\"Advanced\" value=1>\n");
+ }
+
+ printf("</FORM>\n");
+}
+
+/* display a shares editing page */
+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);
+
+ printf("<H2>Share Parameters</H2>\n");
+
+ if (cgi_variable("Advanced") && !cgi_variable("Basic"))
+ advanced = 1;
+
+ if (cgi_variable("Commit") && snum >= 0) {
+ commit_parameters(snum);
+ save_reload();
+ }
+
+ if (cgi_variable("Delete") && snum >= 0) {
+ lp_remove_service(snum);
+ save_reload();
+ share = NULL;
+ snum = -1;
+ }
+
+ if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
+ lp_copy_service(GLOBALS_SNUM, share);
+ save_reload();
+ snum = lp_servicenumber(share);
+ }
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ printf("<table>\n");
+ printf("<tr><td><input type=submit name=selectshare value=\"Choose Share\"></td>\n");
+ printf("<td><select name=share>\n");
+ if (snum < 0)
+ 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)) {
+ printf("<option %s value=\"%s\">%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ }
+ }
+ printf("</select></td></tr><p>");
+
+ printf("<tr><td><input type=submit name=createshare value=\"Create Share\"></td>\n");
+ printf("<td><input type=text size=30 name=newshare></td></tr>\n");
+ printf("</table>");
+
+
+ if (snum >= 0) {
+ printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
+ printf("<input type=submit name=\"Delete\" value=\"Delete Share\">\n");
+ if (advanced == 0) {
+ printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
+ } else {
+ printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
+ }
+ printf("<p>\n");
+ }
+
+ if (snum >= 0) {
+ printf("<table>\n");
+ show_parameters(snum, 1, advanced, 0);
+ printf("</table>\n");
+ }
+
+ if (advanced) {
+ printf("<input type=hidden name=\"Advanced\" value=1>\n");
+ }
+
+ printf("</FORM>\n");
+}
+
+
+/* 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);
+
+ printf("<H2>Printer Parameters</H2>\n");
+
+ if (cgi_variable("Advanced") && !cgi_variable("Basic"))
+ advanced = 1;
+
+ if (cgi_variable("Commit") && snum >= 0) {
+ commit_parameters(snum);
+ save_reload();
+ }
+
+ if (cgi_variable("Delete") && snum >= 0) {
+ lp_remove_service(snum);
+ save_reload();
+ share = NULL;
+ snum = -1;
+ }
+
+ if (cgi_variable("createshare") && (share=cgi_variable("newshare"))) {
+ lp_copy_service(GLOBALS_SNUM, share);
+ snum = lp_servicenumber(share);
+ lp_do_parameter(snum, "print ok", "Yes");
+ save_reload();
+ snum = lp_servicenumber(share);
+ }
+
+ printf("<FORM name=\"swatform\" method=post>\n");
+
+ printf("<table>\n");
+ printf("<tr><td><input type=submit name=selectshare value=\"Choose Printer\"></td>\n");
+ printf("<td><select name=share>\n");
+ if (snum < 0 || !lp_print_ok(snum))
+ 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)) {
+ printf("<option %s value=\"%s\">%s\n",
+ (share && strcmp(share,s)==0)?"SELECTED":"",
+ s, s);
+ }
+ }
+ printf("</select></td></tr><p>");
+
+ printf("<tr><td><input type=submit name=createshare value=\"Create Printer\"></td>\n");
+ printf("<td><input type=text size=30 name=newshare></td></tr>\n");
+ printf("</table>");
+
+
+ if (snum >= 0) {
+ printf("<input type=submit name=\"Commit\" value=\"Commit Changes\">\n");
+ printf("<input type=submit name=\"Delete\" value=\"Delete Printer\">\n");
+ if (advanced == 0) {
+ printf("<input type=submit name=\"Advanced\" value=\"Advanced View\">\n");
+ } else {
+ printf("<input type=submit name=\"Basic\" value=\"Basic View\">\n");
+ }
+ printf("<p>\n");
+ }
+
+ if (snum >= 0) {
+ printf("<table>\n");
+ show_parameters(snum, 1, advanced, 1);
+ printf("</table>\n");
+ }
+
+ if (advanced) {
+ printf("<input type=hidden name=\"Advanced\" value=1>\n");
+ }
+
+ printf("</FORM>\n");
+}
+
+
+
+ int main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ extern FILE *dbf;
+ int opt;
+ char *page;
+ int auth_required = 1;
+
+ /* just in case it goes wild ... */
+ alarm(300);
+
+ dbf = fopen("/dev/null", "w");
+
+ if (!dbf) dbf = stderr;
+
+ while ((opt = getopt(argc, argv,"s:a")) != EOF) {
+ switch (opt) {
+ case 's':
+ pstrcpy(servicesf,optarg);
+ break;
+ case 'a':
+ auth_required = 0;
+ break;
+ }
+ }
+
+ cgi_setup(SWATDIR, auth_required);
+
+ print_header();
+
+ charset_initialise();
+
+ /* if this binary is setuid then run completely as root */
+ setuid(0);
+
+ load_config();
+
+ cgi_load_variables(NULL);
+
+ show_main_buttons();
+
+ page = cgi_pathinfo();
+
+ if (strcmp(page, "globals")==0) {
+ globals_page();
+ } else if (strcmp(page,"shares")==0) {
+ shares_page();
+ } else if (strcmp(page,"printers")==0) {
+ printers_page();
+ } else if (strcmp(page,"status")==0) {
+ status_page();
+ } else if (strcmp(page,"viewconfig")==0) {
+ viewconfig_page();
+ } else {
+ welcome_page();
+ }
+
+ print_footer();
+ return 0;
+}
+
+
diff --git a/swat/README b/swat/README
new file mode 100644
index 00000000000..2810e4e086a
--- /dev/null
+++ b/swat/README
@@ -0,0 +1,126 @@
+This is a brief description of how to install and use the Samba Web
+Administration Tool on your machine.
+
+Please note that SWAT is still being developed so you should not
+expect it to be bug free. You should only install and use it if you
+want to either get a preview of what we are doing with SWAT or you
+want to help in the development of SWAT.
+
+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. Note that SWAT can also be launched via
+the cgi-bin mechanisms of a web server (such as apache) and that is
+described below.
+
+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
+
+If you just want to see a demo of how swat works and don't want to be
+able to actually change any Samba config via swat then you may chose
+to change "root" to some other user that does not have permission to
+write to smb.conf.
+
+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.
+
+
+Running via cgi-bin
+-------------------
+
+To run SWAT via your web servers cgi-bin capability you need to copy
+the swat binary to your cgi-bin directory. Note that you should run
+SWAT either via inetd or via cgi-bin but not both.
+
+Then you need to create a swat directory in your web servers root
+directory and copy the images/* and help/* files into there so that
+they are visible via the URL http://your.web.server/swat/
+
+Next you need to make sure you modify your web servers authentication
+to require a username/pssword for the URL
+http://your.web.server/cgi-bin/swat. Don't forgt this step! If you do
+forget it then you will be allowing anyone to edit your Samba
+configuration which would allow them to easily gain root access on your
+machine.
+
+After testing the authentication you need to change the ownership and
+permissions on the swat binary. It should be owned by root wth the
+setuid bit set. It should be ONLY executable by the user that the web
+server runs as. Make sure you do this carefully!
+
+for example, the following would be correct if the web server ran as
+group "nobody".
+
+-rws--x--- 1 root nobody
+
+You must also realise that this means that any user who can run
+programs as the "nobody" group can run swat and modify your Samba
+config. Be sure to think about this!
+
+
+Launching
+---------
+
+To launch SWAT just run your favourite web browser and point it at
+http://localhost:901/ or http://localhost/cgi-bin/swat/ depending on
+how you installed it.
+
+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.
+
+If installed via inetd then you should be prompted for a
+username/password when you connect. You will need to provide the
+username "root" and the correct root password. More sophisticated
+authentication options are planned for future versions of SWAT.
+
+If installed via cgi-bin then you should receive whatever
+authentication request you configured in your web server.
+
+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/parameters.html b/swat/help/parameters.html
new file mode 100644
index 00000000000..b1f80a17e72
--- /dev/null
+++ b/swat/help/parameters.html
@@ -0,0 +1,2260 @@
+<HTML>
+<BODY>
+
+<H1 ALIGN=CENTER>SWAT Parameters help</H1>
+
+<hr>
+
+<H3><A NAME="admin users">admin users (S)</A></H3>
+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>
+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>
+<B>Default:</B> no admin users <P>
+<B>Example:</B> admin users = jason <P>
+
+<H3><A NAME="announce as">announce as (G)</A></H3>
+This specifies what type of server nmbd will announce itself as in browse
+lists. By default this is set to Windows NT. The valid options are "NT",
+"Win95" or "WfW" meaining Windows NT, 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>
+<B>Default:</B> announce as = NT <P>
+<B>Example:</B> announce as = Win95 <P>
+
+<H3><A NAME="announce version">announce version (G)</A></H3>
+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>
+<B>Default:</B> announce version = 4.2 <P>
+<B>Example:</B> announce version = 2.0 <P>
+
+<H3><A NAME="alternate permissions">alternate permissions (S)</A></H3>
+This option affects the way the "read only" DOS attribute is produced for
+UNIX files. If this is No then the read only bit is set for files on
+writeable shares which the user cannot write to. <P>
+If this is Yes then "read only" is set for files when the user write bit is
+not set. <P>
+The latter behaviour is useful 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. <P>
+<B>Default:</B> alternate permissions = no <P>
+<B>Example:</B> alternate permissions = yes <P>
+
+<H3><A NAME="available">available (S)</A></H3>
+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. <P>
+<B>Default:</B> available = yes <P>
+<B>Example:</B> available = no <P>
+
+<H3><A NAME="bind interfaces only">bind interfaces only (G)</A></H3>
+This global parameter (new for 1.9.18) allows the Samba admin to limit what
+interfaces on a machine will serve smb requests. If affects file service
+(smbd) and name service (nmbd) in slightly different ways. <P>
+For name service it causes nmbd to bind to ports 137 and 138 on the interfaces
+listed in the 'interfaces' parameter. nmbd 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 nmbd will service name requests on
+all of these sockets. If "bind interfaces only" is set then nmbd 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
+<A HREF="#interfaces">interfaces</A> parameter list. As unicast packets are
+received on the other sockets it allows nmbd to refuse to serve names to
+machines that send packets that arrive through any interfaces not listed in
+the 'interfaces' list. IP Source address spoofing does defeat this simple
+check, however so it must not be used seriously as a security feature for
+nmbd. <P>
+For file service it causes smbd to bind only to the interface list given in
+the <A HREF="#interfaces">interfaces</A> parameter. This restricts
+the networks that smbd will serve to packets coming in those interfaces.
+Note that you should not use this parameter for machines that are serving
+ppp or other intermittant or non-broadcast network interfaces as it will
+not cope with non-permanent interfaces. <P>
+<B>Default:</B> bind interfaces only = No <P>
+<B>Example:</B> bind interfaces only = Yes <P>
+
+<H3><A NAME="browseable">browseable (S)</A></H3>
+This controls whether this share is seen in the list of available shares
+in a net view and in the browse list. <P>
+<B>Default:</B> browseable = Yes <P>
+<B>Example:</B> browseable = No <P>
+
+<H3><A NAME="browse list">browse list(G)</A></H3>
+This controls whether the smbd will serve a browse list to a client doing a
+NetServerEnum call. Normally set to Yes. You should never need to change
+this. <P>
+<B>Default:</B> browse list = Yes <P>
+
+<H3><A NAME="case sensitive">case sensitive (G)</A></H3>
+Controls whether filenames are case sensitive. If they aren't then Samba must
+do a filename search and match on passed names.<P>
+<B>Default:</B> case sensitive = No <P>
+See the discussion on <A HREF="#NAME MANGLING">NAME MANGLING</A>. <P>
+
+<H3><A NAME="character set">character set (G)</A></H3>
+This allows smbd to map incoming characters from a DOS 850 Code page to
+either a Western European (ISO8859-1) or Easter European (ISO8859-2) code page.
+Normally not set, meaning no filename translation is done. <P>
+<B>Default:</B> character set = <P>
+<B>Example:</B> character set = iso8859-1 <P>
+
+<H3><A NAME="client code page">client code page (G)</A></H3>
+Currently (Samba 1.9.19 and above) this may be set to one of the following
+values: 437, 850, 852, 866, 932, 936, 949, or 950. It specifies the base DOS
+code page that the clients accessing Samba are using. To determine this,
+open a DOS command prompt and type the command "chcp". 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>
+This parameter co-operates with the <A HREF="#valid chars">valid chars</A>
+parameter in determining what characters are valid in filenames
+and how capitalization is done. It has been added as a convenience for
+clients whose code page is either 437 or 850 so a convoluted "valid chars"
+string does not have to be determined. If you set both this parameter and
+the "valid chars" parameter the "client code page" parameter MUST be
+set before the "valid chars" in the smb.conf file. The "valid chars" string
+will then augment the character settings in the "client code page" parameter.
+<P>
+If "client code page" is set to a value other than those listed above, it will
+default to 850. <P>
+See also : <A HREF="#valid chars">valid chars</A>. <P>
+<B>Default:</B> client code page = 850 <P>
+<B>Example:</B> client code page = 437 <P>
+
+<H3><A NAME="coding system">coding system (G)</A></H3>
+<B>Default:</B> coding system = <P>
+
+<H3><A NAME="comment">comment (S)</A></H3>
+This is a text field that is seen next to a share when a client does a net
+view to list what shares are available. <P>
+If you want to set the string that is displayed next to the machine name then
+see the <A HREF="#server string">server string</A> command. <P>
+<B>Default:</B> No comment string <P>
+<B>Example:</B> comment = Fred's Files <P>
+
+<H3><A NAME="create mask">create mask (S)</A></H3>
+A synonym for this parameter is 'create mode'. <P>
+When a file is created, the neccessary 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 *not* set
+here will be removed from the modes set on a file when it is created. <P>
+The default value of this parameter removes the 'group' and 'other' write and
+execute bits from the UNIX modes. <P>
+Following this Samba will bit-wise 'OR' the UNIX mode created from this
+parameter with the value of the
+<A HREF="#force create mode">force create mode</A>
+parameter which is set to 000 by default. <P>
+For Samba 1.9.17 and above this parameter no longer affects directory modes.
+See the parameter <A HREF="#directory mask">directory mask</A> for details. <P>
+See also the <A HREF="#force create mode">force create mode</A> parameter for
+forcing particular mode bits to be set on created files. See also the
+<A HREF="#directory mask">directory mask</A>
+parameter for masking mode bits on created directories. <P>
+<B>Default:</B> create mask = 0744 <P>
+<B>Example:</B> create mask = 0775 <P>
+
+<H3><A NAME="deadtime">deadtime (G)</A></H3>
+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>
+This is useful to stop a server's resources being exhausted by a large number
+of inactive connections. <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>
+Using this parameter with a timeout of a few minutes is recommended for most
+systems. <P>
+A deadtime of zero indicates that no auto-disconnection should be performed.<P>
+<B>Default:</B> deadtime = 0 <P>
+<B>Example:</B> deadtime = 15
+
+<H3><A NAME="default case">default case (S)</A></H3>
+Controls what the default case (upper/lower) is for new filenames.<P>
+See the section on <A HREF="#NAME MANGLING">NAME MANGLING</A> <P>
+<B>Default:</B> default case = lower <P>
+<B>Example:</B> default case = upper <P>
+
+<H3><A NAME="default service">default service (G)</A></H3> A synonym for this
+parameter is 'default'. <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 NOT given in the parameter value (see example below). <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>
+Typically the default service would be a public, read-only service. <P>
+Also note that as of 1.9.14 the apparent service name will be changed to be
+that of the requested service, this is very useful as it allows
+you to use macros like %S to make a wildcard service. <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>
+<B>Example:</B> default service = pub<P>
+<pre>
+[pub]
+ path = /%S
+</pre>
+
+<H3><A NAME="delete readonly">delete readonly (S)</A></H3>
+This parameter allows readonly files to be deleted. This is not normal DOS
+semantics, but is allowed by UNIX. <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>
+<B>Default:</B> delete readonly = No <P>
+<B>Example:</B> delete readonly = Yes <P>
+
+<H3><A NAME="delete veto files">delete veto files (S)</A></H3>
+This option is used when Samba is attempting to delete a directory that
+contains one or more vetoed directories (see the
+<A HREF="#veto files">veto files</A> option). If this option is set to No
+(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>
+If this option is set to Yes, 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 (eg. .AppleDouble) <P>
+Setting 'delete veto files = Yes' allows these directories to be
+transparently deleted when the parent directory is deleted (so long as the
+user has permissions to do so). <P>
+<B>Default:</B> delete veto files = No <P>
+<B>Example:</B> delete veto files = Yes <P>
+See <A HREF="#veto files">veto files</A> <P>
+
+<H3><A NAME="dfree command">dfree command (G)</A></H3>
+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. <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>
+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. <P>
+Note: Your script should NOT be setuid or setgid and should be owned by
+(and writable only by) root! <P>
+<B>Default:</B> By default internal routines for determining the disk capacity
+and remaining space will be used. <P>
+<B>Example:</B> dfree command = /usr/local/samba/bin/dfree <P>
+Where the script dfree (which must be made executable) could be <P>
+<pre>
+ #!/bin/sh
+ df $1 | tail -1 | awk '{print $2" "$4}'
+</pre>
+or perhaps (on Sys V) <P>
+<pre>
+ #!/bin/sh
+ /usr/bin/df -k $1 | tail -1 | awk '{print $3" "$5}'
+</pre>
+Note that you may have to replace the command names with full path names on
+some systems. <P>
+
+<H3><A NAME="directory mask">directory mask (S)</A></H3>
+A synonym for this parameter is 'directory mode'. <P>
+This parameter is the octal modes which are used when converting DOS modes
+to UNIX modes when creating UNIX directories. <P>
+When a directory is created, the neccessary 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 *not*
+set here will be removed from the modes set on a directory when it is
+created. <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>
+Following this Samba will bit-wise 'OR' the UNIX mode created from this
+parameter with the value of the
+<A HREF="#force directory mode">force directory mode</A>
+parameter. This parameter is set to 000 by default (ie. no extra mode bits
+are added). <P>
+See the <A HREF="#force directory mode">force directory mode</A>
+parameter to cause particular mode bits to always be set on created
+directories. <P>
+See also the <A HREF="#create mask">create mask</A> parameter
+for masking mode bits on created files. <P>
+<B>Default:</B> directory mask = 0755 <P>
+<B>Example:</B> directory mask = 0775 <P>
+
+<H3><A NAME="dns proxy">dns proxy (G)</A></H3>
+Specifies that nmbd should (as a WINS server), on finding that a NetBIOS name
+has not been registered, treat the NetBIOS name word-for-word as a DNS name.<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>
+<B>Default:</B> dns proxy = yes <P>
+
+<H3><A NAME="domain admin users">domain admin users (G)</A></H3>
+<P>
+
+<H3><A NAME="domain controller">domain controller (G)</A></H3>
+<h4>This is wrong</h4>
+Specifies the DNS name or IP address of the machine to refer domain logons
+from Win95 machines to. You should never need to set this parameter. <P>
+<B>Default:</B> domain controller = no <P>
+
+<H3><A NAME="domain groups">domain groups (G)</A></H3>
+<P>
+
+<H3><A NAME="domain guest users">domain guest users (G)</A></H3>
+<P>
+
+<H3><A NAME="domain hosts allow">domain hosts allow (G)</A></H3>
+<P>
+
+<H3><A NAME="domain hosts deny">domain hosts deny (G)</A></H3>
+<P>
+
+<H3><A NAME="domain logons">domain logons (G)</A></H3>
+If set to Yes, the Samba server will serve Windows 95 domain
+logons for the workgroup it is in. For more details on setting up this
+feature see the file DOMAINS.txt in the Samba source documentation directory.
+<P>
+<B>Default:</B> domain logons = no <P>
+
+<H3><A NAME="domain master">domain master (G)</A></H3>
+Enable WAN-wide browse list collation. Local master browsers on
+broadcast-isolated subnets will give samba their local browse lists, and
+ask 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. There should only be one "domain master" for
+each workgroup name.<P>
+<B>Default:</B> domain master = no <P>
+
+<H3><A NAME="domain other sid">domain other sid (G)</A></H3>
+<P>
+
+<H3><A NAME="domain sid">domain sid (G)</A></H3>
+<P>
+
+<H3><A NAME="dont descend">dont descend (S)</A></H3>
+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. <P>
+Note that Samba can be very fussy about the exact format of the "dont descend"
+entries. For example you may need "./proc" instead of just "/proc".
+Experimentation is the best policy :-) <P>
+<B>Default:</B> none (i.e., all directories are OK to descend) <P>
+<B>Example:</B> dont descend = /proc,/dev <P>
+
+<H3><A NAME="dos filetimes">dos filetimes (S)</A></H3>
+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 smbd is acting on
+behalf of is not the file owner. Setting this option to Yes allows DOS
+semantics and smbd will change the file timstamp as DOS requires. This is a
+correct implementation of a previous compile-time options (UTIME_WORKAROUND)
+which was broken and is now removed. <P>
+<B>Default:</B> dos filetimes = No <P>
+<B>Example:</B> dos filetimes = Yes <P>
+
+<H3><A NAME="dos filetime resolution">dos filetime resolution (S)</A></H3>
+Under the DOS and Windows FAT filesystem, the finest granulatity 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 smbd. <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>
+<B>Default:</B> dos filetime resolution = No <P>
+<B>Example:</B> dos filetime resolution = Yes <P>
+
+<H3><A NAME="encrypt passwords">encrypt passwords (G)</A></H3>
+This boolean controls whether encrypted passwords will be negotiated with
+the client. Note that Windows NT 4.0 SP3 and above will by default expect
+encrypted passwords unless a registry entry is changed. To use encrypted
+passwords in Samba see the file docs/ENCRYPTION.txt. <P>
+<B>Default:</B> encrypt passwords = No <P>
+
+<H3><A NAME="exec">exec (S)</A></H3>
+A synonym for this is preexec. <P>
+This option specifies a command to be run whenever a connection is made to
+the service. It takes the usual substitutions. <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>
+exec = csh -c 'echo \"Welcome to %S!\" | \ /usr/local/samba/bin/smbclient -M %m -I %I' &amp; <P>
+Of course, this could get annoying after a while :-) <P>
+See also <A HREF="#postexec">postexec</A> <P>
+<B>Default:</B> none (no command executed) <P>
+<B>Example:</B> exec = echo \"%u connected to %S from %m (%I)\" &gt;&gt; /tmp/log <P>
+
+
+<H3><A NAME="fake directory create times">fake directory create times (S)</A></H3>
+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>
+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>
+However, Unix time semantics mean that the create time reported by Samba
+will be updated whenever a file is created or deleted in the directory.
+NMAKE therefore finds all object files in the object directory bar the last
+one built are out of date compared to the directory and rebuilds them.
+Enabling this option ensures directories always predate their contents and
+an NMAKE build will proceed as expected. <P>
+<B>Default:</B> fake directory create times = No <P>
+<B>Example:</B> fake directory create times = Yes <P>
+
+<H3><A NAME="fake oplocks">fake oplocks (S)</A></H3>
+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>
+When you set "fake oplocks = yes" Samba will always grant oplock requests
+no matter how many clients are using the file. <P>
+By enabling this option 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. Use this option carefully! <P>
+It is generally much better to use the real oplock support except for
+physically read-only media such as CDROMs. <P>
+<B>Default:</B> fake oplocks = No <P>
+<B>Example:</B> fake oplocks = Yes <P>
+
+<H3><A NAME="follow symlinks">follow symlinks (S)</A></H3>
+This parameter allows the Samba administrator to stop smbd 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 /etc/pasword in their home directory for instance.
+However it will slow filename lookups down slightly. <P>
+<B>Default:</B> follow symlinks = Yes (smbd will follow symbolic links)<P>
+
+<H3><A NAME="force create mode">force create mode (S)</A></H3>
+This parameter specifies a set of UNIX mode bit permissions that will *always*
+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. The modes in this
+parameter are bitwise 'OR'ed onto the file mode after the mask set in the
+<A HREF="#create mask">create mask</A> parameter is applied. <P>
+See also the parameter <A HREF="#create mask">create mask</A> for details
+on masking mode bits on created files. <P>
+<B>Default:</B> force create mode = 000 <P>
+<B>Example:</B> force create mode = 0755 <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>
+
+<H3><A NAME="force directory mode">force directory mode (S)</A></H3>
+This parameter specifies a set of UNIX mode bit permissions that will *always*
+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 octel) 0000 which will not add any extra permission bits
+to a created directory. This operation is done after the mode mask in the
+parameter <A HREF="#directory mask">directory mask</A> is applied. <P>
+See also the parameter <A HREF="#directory mask">directory mask</A>
+for details on masking mode bits on created directories. <P>
+<B>Default:</B> force directory mode = 000 <P>
+<B>Example:</B> force directory mode = 0755 <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>
+
+<H3><A NAME="force group">force group (S)</A></H3>
+This specifies a group name that all connections to this service should be
+made as. This may be useful for sharing files. <P>
+<B>Default:</B> no forced group <P>
+<B>Example:</B> force group = agroup <P>
+
+<H3><A NAME="force user">force user (S)</A></H3>
+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. <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. <P>
+<B>Default:</B> no forced user <P>
+<B>Example:</B> force user = auser <P>
+
+<H3><A NAME="getwd cache">getwd cache (G)</A></H3>
+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 No. <P>
+<B>Default:</B>getwd cache = No <P>
+<B>Example:</B>getwd cache = Yes <P>
+
+<H3><A NAME="guest account">guest account (S)</A></H3>
+This is a username which will be used for access to services which are
+specified as <A HREF="#guest ok">guest ok</A>. 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, the specified
+username overrides this one. <P>
+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
+<B>lpr</B>. <P>
+Note that as of version 1.9 of Samba this option may be set differently
+for each service. <P>
+<B>Default:</B>specified at compile time <P>
+<B>Example:</B>guest account = nobody
+
+<H3><A NAME="guest ok">guest ok (S)</A></H3>
+A synonym for this parameter is 'public'. <P>
+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. <P>
+See the section below on
+<A HREF="#USERNAME/PASSWORD VALIDATION">USERNAME/PASSWORD VALIDATION</A>
+for more information about this option. <P>
+<B>Default:</B> guest ok = No <P>
+<B>Example:</B> guest ok = Yes
+
+<H3><A NAME="guest only">guest only (S)</A></H3>
+If this parameter is 'Yes' for a service, then only guest connections to the
+service are permitted. This parameter will have no affect if
+<A HREF="#guest ok">guest ok</A> is not set for the service. <P>
+See the section below on
+<A HREF="#USERNAME/PASSWORD VALIDATION">USERNAME/PASSWORD VALIDATION</A> for
+more information about this option. <P>
+<B>Default:</B> guest only = No <P>
+<B>Example:</B> guest only = Yes
+
+<H3><A NAME="hide dot files">hide dot files (S)</A></H3>
+This is a boolean parameter that controls whether files starting with a dot
+appear as hidden files. <P>
+<B>Default:</B> hide dot files = Yes <P>
+<B>Example:</B> hide dot files = No <P>
+
+<H3><A NAME="hide files">hide files (S)</A></H3>
+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>
+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>
+Each entry must be a unix path, not a DOS path and must not include the unix
+directory separator "/". <P>
+Note that the case sensitivity option is applicable in hiding files. <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>
+See also <A HREF="#hide dot files">hide dot files</A>,
+<A HREF="#veto files">veto files</A> and
+<A HREF="#case sensitive">case sensitive</A> <P>
+<B>Default</B> No files or directories are hidden by this option
+(dot files are hidden by default because of the "hide dot files" option). <P>
+<B>Example</B> hide files = /.*/DesktopFolderDB/TrashFor%m/resource.frk/ <P>
+The above example is based on files that the Macintosh client (DAVE) creates
+for internal use, and also still hides all files beginning with a dot. <P>
+
+<H3><A NAME="homedir map">homedir map (G)</A></H3>
+If <A HREF="#NIS homedir">NIS homedir</A> is Yes, 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>
+&nbsp;&nbsp;&nbsp;&nbsp;username server:/some/file/system <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>
+NB: The -DNETGROUP option is required in the Makefile for option
+to work and on some architectures the line -lrpcsvc needs to be added to
+the LIBSM variable. This is required for Solaris 2, FreeBSD and HPUX. <P>
+See also <A HREF="#NIS homedir">NIS homedir</A> <P>
+<B>Default:</B> homedir map = auto.home <P>
+<B>Example:</B> homedir map = amd.homedir
+
+<H3><A NAME="hosts allow">hosts allow (S)</A></H3>
+A synonym for this parameter is 'allow hosts'. <P>
+This parameter is a comma delimited set of hosts which are permitted to access
+a service. <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>
+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
+"hosts allow = 150.203.5.". <P>
+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: <P>
+Example 1: allow all IPs in 150.203.*.* except one <P>
+&nbsp;&nbsp;hosts allow = 150.203. EXCEPT 150.203.6.66 <P>
+Example 2: allow hosts that match the given network/netmask <P>
+&nbsp;&nbsp;hosts allow = 150.203.15.0/255.255.255.0 <P>
+Example 3: allow a couple of hosts <P>
+&nbsp;&nbsp;hosts allow = lapland, arvidsjaur <P>
+Example 4: allow only hosts in netgroup "foonet" or localhost, but deny
+access from one particular host <P>
+&nbsp;&nbsp;hosts allow = @foonet, localhost<P>
+&nbsp;&nbsp;hosts deny = pirate <P>
+Note that access still requires suitable user-level passwords. <P>
+See <B>testparm</B>(1) for a way of testing your host access to see if it
+does what you expect. <P>
+<B>Default:</B> none (i.e., all hosts permitted access) <P>
+<B>Example:</B> hosts allow = 150.203.5. myhost.mynet.edu.au<P>
+
+<H3><A NAME="hosts deny">hosts deny (S)</A></H3>
+A synonym for this parameter is 'deny hosts'. <P>
+This is the opposite of <A HREF="#hosts allow">hosts allow</A> - 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. <P>
+<B>Default:</B> none (i.e., no hosts specifically excluded) <P>
+<B>Example:</B>hosts deny = 150.203.4. badhost.mynet.edu.au <P>
+
+<H3><A NAME="hosts equiv">hosts equiv (G)</A></H3>
+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>
+This is not be confused with <A HREF="#hosts allow">hosts allow</A> which is
+about hosts access to services and is more useful for guest services.
+<B>hosts equiv</B> may be useful for NT clients which will not supply
+passwords to samba. <P>
+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 :-) <P>
+<B>Default</B> No host equivalences <P>
+<B>Example</B> hosts equiv = /etc/hosts.equiv <P>
+
+<H3><A NAME="include">include (G)</A></H3>
+This allows you to include one config file
+inside another. The file is included literally, as though typed in place. <P>
+It takes the standard substitutions, except %u, %P and %S <P>
+
+<H3><A NAME="interfaces">interfaces (G)</A></H3>
+This option allows you to setup multiple network interfaces, so that
+Samba can properly handle browsing on all interfaces. <P>
+The option takes a list of ip/netmask pairs. The netmask may either be a
+bitmask, or a bitlength. <P>
+For example, the following line: <P>
+&nbsp;&nbsp;interfaces = 192.168.2.10/24 192.168.3.10/24 <P>
+would configure two network interfaces with IP addresses 192.168.2.10 and
+192.168.3.10. The netmasks of both interfaces would be set to 255.255.255.0.<P>
+You could produce an equivalent result by using: <P>
+&nbsp;&nbsp;interfaces = 192.168.2.10/255.255.255.0 192.168.3.10/255.255.255.0<P>
+if you prefer that format. <P>
+If this option is not set then Samba will attempt to find a primary interface,
+but won't attempt to configure more than one interface. <P>
+
+<H3><A NAME="invalid users">invalid users (S)</A></H3>
+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. <P>
+A name starting with @ is interpreted as a UNIX group. <P>
+The current servicename is substituted for %S. This is useful in the [homes]
+section. <P>
+See also <A HREF="#valid users">valid users</A> <P>
+<B>Default</B> No invalid users <P>
+<B>Example</B> invalid users = root fred admin @wheel <P>
+
+<H3><A NAME="keepalive">keepalive (G)</A></H3>
+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. <P>
+<B>Default:</B> keep alive = 300 <P>
+<B>Example:</B> keep alive = 60 <P>
+
+<H3><A NAME="lm announce">lm announce (G)</A></H3>
+This parameter determines if Samba 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, 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 <A HREF="#lm interval">lm interval</A>. 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 'lm interval' parameter<P>
+See also <A HREF="#lm interval">lm interval</A>. <P>
+<B>Default:</B> lm announce = Auto <P>
+<B>Example:</B> lm announce = True <P>
+
+<H3><A NAME="lm interval">lm interval (G)</A></H3>
+If Samba is set to produce Lanman announce broadcasts needed by OS/2 clients
+(see the <A HREF="#lm announce">lm announce</A> parameter) 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 <A HREF="#lm announce">lm announce</A> parameter. <P>
+See also <A HREF="#lm announce">lm announce</A>. <P>
+<B>Default:</B> lm interval = 60 <P>
+<B>Example:</B> lm interval = 120 <P>
+
+<H3><A NAME="load printers">load printers (G)</A></H3>
+A boolean variable that controls whether all printers in the printcap
+will be loaded for browsing by default. <P>
+<B>Default:</B> load printers = Yes <P>
+<B>Example:</B> load printers = No <P>
+
+<H3><A NAME="local master">local master (G)</A></H3>
+This option allows nmbd to become a local master browser on a subnet. If set
+to No then nmbd 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 Yes. Setting this value to Yes doesn't mean that Samba will become the local
+master browser on a subnet, just that the nmbd will participate in elections
+for local master browser. <P>
+<B>Default:</B> local master = yes <P>
+
+<H3><A NAME="lock dir">lock dir (G)</A></H3>
+This option specifies the directory where lock files will be placed.
+The lock files are used to implement the
+<A HREF="#max connections">max connections</A> option. <P>
+<B>Default:</B> lock dir = /tmp/samba <P>
+<B>Example:</B> lock dir = /usr/local/samba/var/locks <P>
+
+<H3><A NAME="locking">locking (S)</A></H3>
+This controls whether or not locking will be performed by the server in
+response to lock requests from the client. <P>
+If set to No, all lock and unlock requests will appear to succeed and all
+lock queries will indicate that the queried lock is clear. <P>
+If set to Yes, real locking will be performed by the server. <P>
+This option may be particularly useful for read-only filesystems which do not
+need locking (such as CDROM drives). <P>
+Be careful about disabling locking either globally or in a specific
+service, as lack of locking may result in data corruption. <P>
+<B>Default:</B> locking = Yes <P>
+<B>Example:</B> locking = No <P>
+
+<H3><A NAME="log file">log file (G)</A></H3>
+This options allows you to override the name of the Samba log file (also
+known as the debug file). <P>
+This option takes the standard substitutions, allowing you to have separate
+log files for each user or machine. <P>
+<B>Example:</B> log file = /usr/local/samba/var/log.%m <P>
+
+<H3><A NAME="log level">log level (G)</A></H3>
+A synonym for this is debuglevel<P>
+The value of the parameter (an integer) allows the logging level (debug level)
+to be specified in the <B>smb.conf</B> file. This is to give greater
+flexibility in the configuration of the system. <P>
+The default will be the logging level specified on the command line. <P>
+<B>Example:</B> log level = 3
+
+<H3><A NAME="logon drive">logon drive (G)</A></H3>
+This parameter specifies the local path to which the home directory will be
+connected (see <A HREF="#logon home">logon home</A>) and is only used by NT
+Workstations. <P>
+<B>Example:</B> logon drive = h: <P>
+
+<H3><A NAME="logon home">logon home (G)</A></H3>
+This parameter specifies the home directory location when a Win95 or NT
+Workstation logs into a Samba PDC. It allows you to do "NET USE H: /HOME"
+from a command prompt, for example. <P>
+This option takes the standard substitutions, allowing you to have separate
+logon scripts for each user or machine. <P>
+<B>Default:</B> logon home = "\\%N\%U" <P>
+<B>Example:</B> logon home = "\\remote_smb_server\%U" <P>
+
+<H3><A NAME="logon path">logon path (G)</A></H3>
+This parameter specifies the home directory where roaming profiles (USER.DAT
+/ USER.MAN files for Windows 95) are stored. <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 "desktop", "start menu", "nethood" and "programs" folders, and their
+contents, are loaded and displayed on your Windows 95 client. <P>
+The share and the path must be readable by the user for the preferences and
+directories to be loaded onto the Windows 95 client. The share must be
+writeable when the user logs in for the first time, in order that the
+Windows 95 client can create the user.dat and other directories. <P>
+Thereafter, the directories and any of contents can, if required, be
+made read-only. It is not adviseable that the USER.DAT file be made read-only
+- rename it to USER.MAN to achieve the desired effect (a MANdatory profile). <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
+\\%N\HOMESprofile_path will cause problems). <P>
+This option takes the standard substitutions, allowing you to have separate
+logon scripts for each user or machine. <P>
+<B>Default:</B> logon path = \\%N\%U\profile <P>
+<B>Example:</B> logon path = \\PROFILESERVER\HOME_DIR\%U\PROFILE <P>
+
+<H3><A NAME="logon script">logon script (G)</A></H3>
+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>
+The script must be a relative path to the [netlogon] service. If the
+[netlogon] service specifies a path of /usr/local/samba/netlogon, and logon
+script = STARTUP.BAT, then file that will be downloaded is: <P>
+&nbsp;&nbsp;<B>/usr/local/samba/netlogon/STARTUP.BAT</B> <P>
+The contents of the batch file is entirely your choice. A suggested command
+would be to add NET TIME \\SERVER /SET /YES, to force every machine to
+synchronise clocks with the same time server. Another use would be to add
+NET USE U: \\SERVER\UTILS for commonly used utilities, or
+NET USE Q: \\SERVER\ISO9001_QA. <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. <P>
+This option takes the standard substitutions, allowing you to have separate
+logon scripts for each user or machine. <P>
+<B>Example:</B> logon script = scripts/%U.bat <P>
+
+<H3><A NAME="lppause command">lppause command (S)</A></H3>
+This parameter specifies the command to be executed on the server host in
+order to stop printing or spooling a specific print job. <P>
+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 won't be
+sent to the printer. See also
+<A HREF="#lpresume command">lpresume command</A>.<P>
+If a %p is given then the printername is put in its place. A %j is replaced
+with the job number (an integer). On HPUX (see
+<A HREF="#printing">printing</A>=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. <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>
+<B>Default:</B> Currently no default value is given to this string <P>
+<B>Example for HPUX:</B> lppause command = /usr/bin/lpalt %p-%j -p0 <P>
+
+<H3><A NAME="lpq cache time">lpq cache time (G)</A></H3>
+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. <P>
+The cache files are stored in /tmp/lpq.xxxx where xxxx is a hash of the lpq
+command in use. <P>
+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. <P>
+A value of 0 will disable cacheing completely. <P>
+<B>Default:</B> lpq cache time = 10 <P>
+<B>Example:</B> lpq cache time = 30 <P>
+
+<H3><A NAME="lpq command">lpq command (S)</A></H3>
+This parameter specifies the command to be executed on the server host
+in order to obtain "lpq"-style printer status information. <P>
+This command should be a program or script which takes a printer name as its
+only parameter and outputs printer status information. <P>
+Currently six styles of printer status information are supported; BSD, SYSV,
+AIX, HPUX, QNX, LPRNG and PLP. This covers most UNIX systems. You control
+which type is expected using the <A HREF="#printing">printing</A> option. <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>
+If a %p is given then the printername is put in its place. Otherwise it is
+placed at the end of the command. <P>
+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. <P>
+<B>Default:</B> depends on the setting of <A HREF="#printing">printing</A><P>
+<B>Example:</B> lpq command = /usr/bin/lpq %p <P>
+
+<H3><A NAME="lpresume command">lpresume command (S)</A></H3>
+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>
+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="#lppause command">lppause command</A>. <P>
+If a %p is given then the printername is put in its place.
+A %j is replaced with the job number (an integer). <P>
+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. <P>
+<B>Default:</B> Currently no default value is given to this string <P>
+<B>Example for HPUX:</B> lpresume command = /usr/bin/lpalt %p-%j -p2 <P>
+
+<H3><A NAME="lprm command">lprm command (S)</A></H3>
+This parameter specifies the command to be executed on the server host in
+order to delete a print job. <P>
+This command should be a program or script which takes a printer name
+and job number, and deletes the print job. <P>
+Currently seven styles of printer control are supported; BSD, SYSV, AIX HPUX,
+QNX, LPRNG and PLP. This covers most UNIX systems. You control which type is
+expected using the <A HREF="#printing">printing</A> option. <P>
+If a %p is given then the printername is put in its place. A
+%j is replaced with the job number (an integer). <P>
+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. <P>
+<B>Default:</B> depends on the setting of <A HREF="#printing">printing</A><P>
+<B>Example 1:</B>lprm command = /usr/bin/lprm -P%p %j <P>
+<B>Example 2:</B>lprm command = /usr/bin/cancel %p-%j <P>
+
+<H3><A NAME="magic output">magic output (S)</A></H3>
+This parameter specifies the name of a file which will contain output
+created by a magic script (see <A HREF="#magic script">magic script</A>
+below). <P>
+Warning: If two clients use the same magic script in the same directory the
+output file content is undefined. <P>
+<B>Default:</B> magic output = &lt;magic script name&gt;.out <P>
+<B>Example:</B> magic output = myfile.txt <P>
+
+<H3><A NAME="magic script">magic script (S)</A></H3>
+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>
+Scripts executed in this way will be deleted upon completion, permissions
+permitting. <P>
+If the script generates output, output will be sent to the file specified by
+the <A HREF="#magic output">magic output</A> parameter. <P>
+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. <P>
+Magic scripts are EXPERIMENTAL and should NOT be relied upon. <P>
+<B>Default:</B> None. Magic scripts disabled. <P>
+<B>Example:</B> magic script = user.csh <P>
+
+<H3><A NAME="mangle case">mangle case (S)</A></H3>
+Controls if names that have characters that aren't of the "default" case are
+mangled. <P>
+See the section on <A HREF="#NAME MANGLING">NAME MANGLING</A> <P>
+
+<H3><A NAME="mangled map">mangled map (S)</A></H3>
+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 extensions 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. <P>
+So to map 'html' to 'htm' you put: <P>
+mangled map = (*.html *.htm) <P>
+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 *) <P>
+<B>default:</B> no mangled map <P>
+<B>Example:</B> mangled map = (*;1 *) <P>
+
+<H3><A NAME="mangled names">mangled names (S)</A></H3>
+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>
+See the section on <A HREF="#NAME MANGLING">NAME MANGLING</A> for
+details on how to control the mangling process. <P>
+If mangling is used then the mangling algorithm is as follows:
+<blockquote>- 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>
+- 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>
+Note that the character to use may be specified using the
+<A HREF="#mangling char">mangling char</A> option, if you don't like ~. <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>
+- 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).
+</blockquote>
+The two-digit hash value consists of upper case alphanumeric characters. <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>
+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. <P>
+<B>Default:</B> mangled names = Yes <P>
+<B>Example:</B> mangled names = No <P>
+
+<H3><A NAME="mangling char">mangling char (S)</A></H3>
+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. <P>
+<B>Default:</B> mangling char = ~ <P>
+<B>Example:</B> mangling char = ^ <P>
+
+<H3><A NAME="mangled stack">mangled stack (G)</A></H3>
+This parameter controls the number of mangled names that should be cached in
+the Samba server. <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>
+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). <P>
+It is not possible to absolutely guarantee correct long file names, so be
+prepared for some surprises! <P>
+<B>Default:</B> mangled stack = 50 <P>
+<B>Example:</B> mangled stack = 100 <P>
+
+<H3><A NAME="map archive">map archive (S)</A></H3>
+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>
+Note that this requires the 'create mask' to be set such
+that owner execute bit is not masked out (ie. it must include 100). See
+the parameter <A HREF="#create mask">create mask</A> for details. <P>
+<B>Default:</B> map archive = Yes <P>
+<B>Example:</B> map archive = No <P>
+
+<H3><A NAME="map hidden">map hidden (S)</A></H3>
+This controls whether DOS style hidden files should be mapped to the UNIX
+world execute bit. <P>
+Note that this requires the 'create mask' to be set such that the world
+execute bit is not masked out (ie. it must include 001). See the parameter
+<A HREF="#create mask">create mask</A> for details. <P>
+<B>Default:</B> map hidden = No <P>
+<B>Example:</B> map hidden = Yes <P>
+
+<H3><A NAME="map system">map system (S)</A></H3>
+This controls whether DOS style system files should be mapped to the UNIX
+group execute bit. <P>
+Note that this requires the 'create mask' to be set such that the group
+execute bit is not masked out (ie. it must include 010). See the parameter
+<A HREF="#create mask">create mask</A> for details. <P>
+<B>Default:</B> map system = No <P>
+<B>Example:</B> map system = Yes <P>
+
+<H3><A NAME="max connections">max connections (S)</A></H3>
+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. <P>
+Record lock files are used to implement this feature. The lock files will be
+stored in the directory specified by the
+<A HREF="#lock dir">lock dir</A> option. <P>
+<B>Default:</B> max connections = 0 <P>
+<B>Example:</B> max connections = 10 <P>
+
+<H3><A NAME="max disk size">max disk size (G)</A></H3>
+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>
+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
+"max disk size". <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>
+A "max disk size" of 0 means no limit. <P>
+<B>Default:</B> max disk size = 0 <P>
+<B>Example:</B> max disk size = 1000 <P>
+
+<H3><A NAME="max log size">max log size (G)</A></H3>
+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. <P>
+A size of 0 means no limit. <P>
+<B>Default:</B> max log size = 5000 <P>
+<B>Example:</B> max log size = 1000 <P>
+
+<H3><A NAME="max mux">max mux (G)</A></H3>
+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>
+<B>Default:</B> max mux = 50 <P>
+
+<H3><A NAME="max packet">max packet (G)</A></H3>
+A synonym for this parameter is 'packet size'. <P>
+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. <P>
+
+<H3><A NAME="max ttl">max ttl (G)</A></H3>
+This option tells nmbd what the default 'time to live' of NetBIOS names should
+be (in seconds) when nmbd is requesting a name using either a broadcast
+or from a WINS server. You should never need to change this parameter. <P>
+<B>Default:</B> max ttl = 14400 <P>
+
+<H3><A NAME="max wins ttl">max wins ttl (G)</A></H3>
+This option tells nmbd when acting as a WINS server
+(<A HREF="#wins support">wins support</A> = Yes) what the maximum 'time to
+live' of NetBIOS names that nmbd will grant will be (in seconds). You should
+never need to change this parameter. The default is 3 days (259200
+seconds). <P>
+<B>Default:</B> max wins ttl = 259200 <P>
+
+<H3><A NAME="max xmit">max xmit (G)</A></H3>
+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>
+<B>Default:</B> max xmit = 65535 <P>
+<B>Example:</B> max xmit = 8192 <P>
+
+<H3><A NAME="message command">message command (G)</A></H3>
+This specifies what command to run when the server receives a WinPopup style
+message. <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>
+What I use is: <P>
+message command = csh -c 'xedit %s;rm %s' &amp; <P>
+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 &amp; on the end. If it doesn't return immediately then your PCs may
+freeze when sending messages (they should recover after 30secs, hopefully). <P>
+All messages are delivered as the global guest user. The command takes
+the standard substitutions, although %u won't work (%U may be better in
+this case). <P>
+Apart from the standard substitutions, some additional ones apply. In
+particular: <P>
+%s = the filename containing the message <P>
+%t = the destination that the message was sent to (probably the server name) <P>
+%f = who the message is from <P>
+You could make this command send mail, or whatever else takes your fancy.
+Please let me know of any really interesting ideas you have. <P>
+Here's a way of sending the messages as mail to root: <P>
+message command = /bin/mail -s 'message from %f on %m' root &lt; %s; rm %s <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>
+If you want to silently delete it then try "message command = rm %s". <P>
+For the really adventurous, try something like this: <P>
+message command = csh -c 'csh &lt; %s |&amp; /usr/local/samba/bin/smbclient \
+ -M %m; rm %s' &amp; <P>
+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 :-) <P>
+<B>Default:</B> no message command <P>
+<B>Example:</B> message command = csh -c 'xedit %s;rm %s' &amp; <P>
+
+<H3><A NAME="min print space">min print space (S)</A></H3>
+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. <P>
+<B>Default:</B> min print space = 0 <P>
+<B>Example:</B> min print space = 2000 <P>
+
+<H3><A NAME="min wins ttl">min wins ttl (G)</A></H3>
+This option tells nmbd when acting as a WINS server
+(<A HREF="#wins support">wins support</A> = Yes) what the
+minimum 'time to live' of NetBIOS names that nmbd will grant will be (in
+seconds). You should never need to change this parameter. The default is
+6 hours (21600 seconds). <P>
+<B>Default:</B> min wins ttl = 21600 <P>
+
+<H3><A NAME="name resolve order">name resolve order (G)</A></H3>
+This option is used by the programs smbd, nmbd and smbclient
+to determine what naming services and in what order to resolve host names
+to IP addresses. This option is most useful in smbclient. The option takes
+a space separated string of different name resolution options. These are
+"lmhosts", "host", "wins" and "bcast". They cause names to be resolved
+as follows : <P>
+<pre>
+lmhosts Lookup an IP address in the Samba lmhosts file.
+host Do a standard host name to IP address resolution, using the
+ system /etc/hosts, NIS, or DNS lookups. This method of name
+ resolution is operating system depended (for instance on Solaris
+ this may be controlled by the /etc/nsswitch.conf file).
+wins Query a name with the IP address listed in the "wins server ="
+ parameter. If no WINS server has been specified this method will
+ be ignored.
+bcast Do a broadcast on each of the known local
+ interfaces listed in the "interfaces =" parameter. This is the
+ least reliable of the name resolution methods as it depends
+ on the target host being on a locally connected subnet.
+</pre>
+The default order is lmhosts, host, wins, bcast and these name resolution
+methods will be attempted in this order. <P>
+This option was first introduced in Samba 1.9.18p4. <P>
+<B>Default:</B> name resolve order = lmhosts host wins bcast <P>
+<B>example:</B> name resolve order = lmhosts bcast host <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>
+
+<H3><A NAME="netbios aliases">netbios aliases (G)</A></H3>
+This is a list of names that nmbd 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>
+See also <A HREF="#netbios name">netbios name</A>. <P>
+<B>Example:</B>netbios aliases = TEST TEST1 TEST2 <P>
+
+<H3><A NAME="netbios name">netbios name (G)</A></H3>
+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>
+See also <A HREF="#netbios aliases">netbios aliases</A>. <P>
+<B>Example:</B> netbios name = MYNAME <P>
+
+<H3><A NAME="NIS homedir">NIS homedir (G)</A></H3>
+Get the home share server from a NIS (or YP) 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, two network hops are required to access
+the home directory and this can be very slow especially with writing via
+Samba to an NFS mounted directory. 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 (or YP) map
+specified in <A HREF="#homedir map">homedir map</A> and return the server
+listed there. <P>
+<B>Default:</B> NIS homedir = No <P>
+<B>Example:</B> NIS homedir = Yes <P>
+
+<H3><A NAME="networkstation user login">networkstation user login (G)</A></H3>
+This global parameter (new for 1.9.18p3) affects server level security. With
+this set (recommended) samba will do a full NetWkstaUserLogon to confirm that
+the client really should have login rights. This can cause problems with
+machines in trust relationships in which case you can disable it here,
+but be warned, we have heard that some NT machines will then allow anyone
+in with any password! Make sure you test it. <P>
+<B>Default:</B> networkstation user login = Yes <P>
+<B>Example:</B> networkstation user login = No <P>
+
+<H3><A NAME="null passwords">null passwords (G)</A></H3>
+Allow or disallow access to accounts that have null passwords. <P>
+<B>Default:</B> null passwords = No <P>
+<B>Example:</B> null passwords = Yes <P>
+
+<H3><A NAME="only user">only user (S)</A></H3>
+This is a boolean option that controls whether connections with usernames not
+in the <A HREF="#username">username</A> list will be allowed. By default this
+option is disabled so a client can supply a username to be used by the
+server. <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 "<A HREF="#username">username</A> = %S" which means your
+"username" list will be just the service name, which for home directories
+is the name of the user. <P>
+<B>Default: </B> only user = No <P>
+<B>Example: </B> only user = Yes <P>
+
+<H3><A NAME="oplocks">oplocks (S)</A></H3>
+This boolean option tells smbd whether to issue oplocks (opportunistic locks)
+to file open requests on this share. The oplock code
+was introduced in Samba 1.9.18 and can dramatically (approx 30% or more)
+improve the speed of access to files on Samba servers. It allows the clients
+to agressively 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 Speed.txt in the Samba docs/
+directory. <P>
+Oplocks may be selectively turned off on certain files on a per share basis.
+See the <A HREF="#veto oplock files">veto oplock files</A> parameter. <P>
+<B>Default:</B> oplocks = Yes <P>
+<B>Example:</B> oplocks = No <P>
+
+<H3><A NAME="os level">os level (G)</A></H3>
+This integer value controls what level Samba advertises itself as for browse
+elections. See BROWSING.txt for details. <P>
+
+<H3><A NAME="passwd chat debug">passwd chat debug (G)</A></H3>
+This boolean specifies if the passwd chat script parameter is run
+in 'debug' mode. In this mode the strings passed to and received from the
+passwd chat are printed in the smbd log with a debug level of 100. This
+is a dangerous option as it will allow plaintext passwords to be seen
+in the smbd log. It is available to help Samba admins debug their passwd
+chat scripts and should be turned off after this has been done. This parameter
+is off by default. <P>
+<B>Example:</B> passwd chat debug = Yes <P>
+<B>Default:</B> passwd chat debug = No <P>
+
+<H3><A NAME="passwd chat">passwd chat (G)</A></H3>
+This string controls 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. <P>
+This chat sequence is often quite site specific, depending
+on what local methods are used for password control (such as NIS+ etc). <P>
+The string can contain the macros %o and %n which are substituted for
+the old and new passwords respectively. It can also contain the standard
+macros \n \r \t and \s to give line-feed, carriage-return, tab and space. <P>
+The string can also contain a * which matches any sequence of characters. <P>
+Double quotes can be used to collect strings with spaces in them into
+a single string. <P>
+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. <P>
+<B>Default:</B> passwd chat = *old*password* %o\n *new*password* %n\n *new*password* %n\n *changed* <P>
+<B>Example:</B> passwd chat = "*Enter OLD password*" %o\n "*Enter NEW password*" %n\n \
+ "*Reenter NEW password*" %n\n "*Password changed*" <P>
+
+<H3><A NAME="passwd program">passwd program (G)</A></H3>
+The name of a program that can be used to set user passwords. <P>
+This is only necessary if you have enabled remote password changing at
+compile time. Any occurrences of %u will be replaced with the user name. <P>
+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. <P>
+<B>Default:</B> passwd program = /bin/passwd <P>
+<B>Example:</B> passwd program = /sbin/passwd %u <P>
+
+<H3><A NAME="password level">password level (G)</A></H3>
+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! <P>
+This parameter defines the maximum number of characters that may be upper
+case in passwords. <P>
+For example, say the password given was "FRED". If password level is set to
+1 (one), the following combinations would be tried if "FRED" failed: "Fred",
+"fred", "fRed", "frEd", "freD". If password level was set to 2 (two), the
+following combinations would also be tried: "FRed", "FrEd", "FreD", "fREd",
+"fReD", "frED". And so on. <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>
+A value of zero will cause only two attempts to be made - the password
+as is and the password in all-lower case. <P>
+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 includes.h file tries to select the right length for your system. <P>
+<B>Default:</B> password level = 0 <P>
+<B>Example:</B> password level = 4 <P>
+
+<H3><A NAME="password server">password server (G)</A></H3>
+By specifying the name of another SMB server (such as a WinNT box) with this
+option, and using "<A HREF="#security">security</A> = server" you can get
+Samba to do all its username/password validation via a remote server. <P>
+This options 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 /etc/hosts. <P>
+Note that with Samba 1.9.18p4 and above the name of the password server is
+looked up using the <A HREF="#name resolve order">name resolve order</A>
+parameter and so may resolved by any method and order described in that
+parameter. <P>
+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. <P>
+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. <P>
+Never point a Samba server at itself for password serving. This will cause a
+loop and could lock up your Samba server! <P>
+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
+<A HREF="#hosts allow">hosts allow</A>! <P>
+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. <P>
+If you are using a WindowsNT server as your password server then you will
+have to ensure that your users are able to login from the Samba server, as
+the network logon will appear to come from there rather than from the users
+workstation. <P>
+
+<H3><A NAME="path">path (S)</A></H3>
+A synonym for this parameter is "directory". <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>
+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. <P>
+Any occurrences of %u in the path will be replaced with the username that the
+client is connecting as. Any occurrences 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. <P>
+Note that this path will be based on
+<A HREF="#root directory">root directory</A> if one was specified.<P>
+<B>Default:</B> none <P>
+<B>Example:</B> path = /home/fred <P>
+
+<H3><A NAME="postexec">postexec (S)</A></H3>
+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>
+An interesting example may be do unmount server resources: <P>
+postexec = /etc/umount /cdrom <P>
+See also <A HREF="#preexec">preexec</A> <P>
+<B>Default:</B> none (no command executed) <P>
+<B>Example:</B> postexec = echo \"%u disconnected from %S from %m (%I)\" &gt;&gt; /tmp/log <P>
+
+<H3><A NAME="postscript">postscript (S)</A></H3>
+This parameter forces a printer to interpret the print files as postscript.
+This is done by adding a %! to the start of print output. <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>
+<B>Default:</B> postscript = No <P>
+<B>Example:</B> postscript = Yes <P>
+
+<H3><A NAME="preferred master">preferred master (G)</A></H3>
+This boolean parameter controls if Samba is a preferred master browser for
+its workgroup. If this is set to Yes, on startup, samba 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
+<A HREF="#domain master">domain master</A> = yes, so that samba can guarantee
+becoming a domain master. <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>
+See <A HREF="#os level">os level</A> = nn <P>
+<B>Default:</B> preferred master = no <P>
+
+<H3><A NAME="preload">preload</A></H3>
+An alias is "auto services". 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>
+Note that if you just want all printers in your printcap file loaded then the
+<A HREF="#load printers">load printers</A> option is easier. <P>
+<B>Default:</B> no preloaded services <P>
+<B>Example:</B> preload = fred lp colorlp <P>
+
+<H3><A NAME="preserve case">preserve case (S)</A></H3>
+This controls if new filenames are created with the case that
+the client passes, or if they are forced to be the "default" case. <P>
+<B>Default:</B> preserve case = no <P>
+See the section on <A HREF="#NAME MANGLING">NAME MANGLING</A> for a fuller
+discussion. <P>
+
+<H3><A NAME="print command">print command (S)</A></H3>
+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. <P>
+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 <A HREF="#printer name">printer name</A> is discussed below. <P>
+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 occurrences of %f get replaced by the spool filename without
+the full path at the front. <P>
+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. <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>
+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>
+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
+<A HREF="#guest account">guest account</A> in the [global] section. <P>
+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. <P>
+print command = echo Printing %s &gt;&gt; /tmp/print.log; lpr -P %p %s; rm %s<P>
+You may have to vary this command considerably depending on how you normally
+print files on your system. <P>
+<B>Default:</B> print command = lpr -r -P %p %s <P>
+<B>Example:</B>print command = /usr/local/samba/bin/myprintscript %p %s <P>
+
+<H3><A NAME="print ok">print ok (S)</A></H3>
+A synonym for this parameter is 'printable'. <P>
+If this parameter is 'Yes', then clients may open, write to
+and submit spool files on the directory specified for the service. <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="#read only">read only</A> parameter controls only non-printing
+access to the resource. <P>
+<B>Default:</B> print ok = No <P>
+<B>Example:</B> print ok = Yes <P>
+
+<H3><A NAME="printcap name">printcap name (G)</A></H3>
+This parameter may be used to override the compiled-in default printcap name
+used by the server (usually /etc/printcap). On SystemV systems that
+use lpstat to list available printers you can use "printcap name = lpstat"
+to automatically obtain lists of available printers. This is the default
+for systems that define SYSV at compile time in Samba (this includes
+most SystemV based systems). If "printcap name" is set to lpstat on these
+systems then Samba will launch "lpstat -v" and attempt to parse the output
+to obtain a printer list. <P>
+A minimal printcap file would look something like this: <P>
+print1|My Printer 1 <BR>
+print2|My Printer 2 <BR>
+print3|My Printer 3 <BR>
+print4|My Printer 4 <BR>
+print5|My Printer 5 <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>
+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. <P>
+<B>Default:</B> printcap name = /etc/printcap <P>
+<B>Example:</B> printcap name = /etc/myprintcap <P>
+
+<H3><A NAME="printer driver">printer driver (S)</A></H3>
+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 WindowsNT then you can use this to automate the setup of
+printers on your system. <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 "printer driver"
+option set and the client will give you a list of printer drivers. The
+appropriate strings are shown in a scrollbox after you have chosen the
+printer manufacturer. <P>
+<B>Example:</B> printer driver = HP LaserJet 4L <P>
+
+<H3><A NAME="printer name">printer name (S)</A></H3>
+A synonym for this parameter is 'printer'. <P>
+This parameter specifies the name of the printer to which print jobs spooled
+through a printable service will be sent. <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>
+<B>Default:</B> none (but may be 'lp' on many systems) <P>
+<B>Example:</B> printer name = laserwriter <P>
+
+<H3><A NAME="printer driver file">printer driver file (G)</A></H3>
+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>
+SAMBA_INSTALL_DIRECTORY/lib/printers.def <P>
+This file is created from Windows 95 'msprint.def' files found on the Windows
+95 client system. For more details on setting up serving of printer drivers
+to Windows 95 clients, see the documentation file docs/PRINTER_DRIVER.txt. <P>
+<B>Default:</B> None (set in compile). <P>
+<B>Example:</B> printer driver file = /usr/local/samba/printers/drivers.def <P>
+Related parameters.
+<A HREF="#printer driver location">printer driver location</A> <P>
+
+<H3><A NAME="printer driver location">printer driver location (S)</A></H3>
+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>
+\\MACHINE\PRINTER$ <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 documentation file
+docs/PRINTER_DRIVER.txt. <P>
+<B>Default:</B> None <P>
+<B>Example:</B> printer driver location = \\MACHINE\PRINTER$ <P>
+Related paramerers.
+<A HREF="#printer driver file">printer driver file</A><P>
+
+<H3><A NAME="printing">printing (S)</A></H3>
+This parameters controls how printer status information is interpreted
+on your system, and also affects the default values for the
+<A HREF="#print command">print command</A>,
+<A HREF="#lpq command">lpq command</A> and
+<A HREF="#lprm command">lprm command</A>. <P>
+Currently six printing styles are supported. They are bsd, sysv, hpux, aix,
+qnx and plp. <P>
+To see what the defaults are for the other print commands when using these
+options use the "testparm" program. <P>
+As of version 1.9.18 of Samba this option can be set on a per printer basis <P>
+<B>Example:</B> printing = sysv <P>
+
+<H3><A NAME="protocol">protocol (G)</A></H3>
+The value of the parameter (a string) is the highest protocol level that will
+be supported by the server. <P>
+Possible values are CORE, COREPLUS, LANMAN1, LANMAN2 and NT1. The relative
+merits of each are discussed in the README file. <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>
+<B>Default:</B> protocol = NT1 <P>
+<B>Example:</B> protocol = LANMAN1 <P>
+
+<H3><A NAME="read bmpx">read bmpx (S)</A></H3>
+<B>Default:</B> read bmpx = Yes <P>
+
+<H3><A NAME="read list">read list (S)</A></H3>
+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="#read only">read only</A> option is set
+to. The list can include group names using the @group syntax. <P>
+See also the <A HREF="#write list">write list</A> option <P>
+<B>Default:</B> read list = <P>
+<B>Example:</B> read list = mary, @students <P>
+
+<H3><A NAME="read only">read only (S)</A></H3>
+Inverted synonyms for this parameter are 'writable' and 'write ok'. <P>
+If this parameter is 'Yes', then users of the service may not create or
+modify files in the service's directory. <P>
+Note that a printable service ('<A HREF="#printable">printable</A> = Yes')
+will ALWAYS allow writing to the directory (user privileges permitting), but
+only via spooling operations. <P>
+<B>Default:</B> read only = Yes <P>
+<B>Examples:</B> read only = No <BR>
+writable = No <BR>
+write ok = Yes <P>
+
+<H3><A NAME="read prediction">read prediction (G)</A></H3>
+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. <P>
+<B>Default:</B> read prediction = No <P>
+<B>Example:</B> read prediction = Yes <P>
+
+<H3><A NAME="read raw">read raw (G)</A></H3>
+This parameter controls whether or not the server will support raw reads when
+transferring data to clients. <P>
+If enabled, raw reads allow reads of 65535 bytes in one packet. This typically
+provides a major performance benefit. <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>
+In general this parameter should be viewed as a system tuning tool and left
+severely alone. See also <A HREF="#write raw">write raw.</A> <P>
+<B>Default:</B> read raw = Yes <P>
+<B>Example:</B> read raw = No <P>
+
+<H3><A NAME="read size">read size (G)</A></H3>
+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. <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>
+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. <P>
+<B>Default:</B> read size = 2048 <P>
+<B>Example:</B> read size = 8192 <P>
+
+<H3><A NAME="remote announce">remote announce (G)</A></H3>
+This option allows you to setup nmbd to periodically announce itself to
+arbitrary IP addresses with an arbitrary workgroup name. <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>
+For example: <P>
+remote announce = 192.168.2.255/SERVERS 192.168.4.255/STAFF <P>
+the above line would cause nmbd 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">workgroup</A> option is
+used instead. <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>
+This option replaces similar functionality from the nmbd lmhosts file. <P>
+
+<H3><A NAME="remote browse sync">remote browse sync (G)</A></H3>
+This option allows you to setup nmbd to periodically request
+synchronisation 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>
+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>
+For example: <P>
+remote browse sync = 192.168.2.255 192.168.4.255 <P>
+the above line would cause nmbd to request the master browser on the
+specified subnets or addresses to synchronise their browse lists with the
+local server. <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 it's
+segment. <P>
+
+<H3><A NAME="revalidate">revalidate (S)</A></H3>
+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. <P>
+If "revalidate" is Yes then the client will be denied automatic access as
+the same username. <P>
+<B>Default:</B> revalidate = No <P>
+<B>Example:</B> revalidate = Yes <P>
+
+<H3><A NAME="root directory">root directory (G)</A></H3>
+Synonyms for this parameter are 'root dir' and 'root'. <P>
+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 <A HREF="#wide links">wide links</A> parameter). <P>
+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. <P>
+<B>Default:</B> root directory = / <P>
+<B>Example:</B> root directory = /homes/smb <P>
+
+<H3><A NAME="root postexec">root postexec (S)</A></H3>
+This is the same as <A HREF="#postexec">postexec</A> except that
+the command is run as root. This is useful for unmounting filesystems (such
+as CDROMS) after a connection is closed. <P>
+
+<H3><A NAME="root preexec">root preexec (S)</A></H3>
+This is the same as <A HREF="#exec">exec</A> except that the command is run
+as root. This is useful for mounting filesystems (such as CDROMS) before a
+connection is finalised. <P>
+
+<H3><A NAME="security">security (G)</A></H3>
+This option affects how clients respond to Samba. <P>
+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.<P>
+The default is "security=SHARE", mainly because that was the only option at
+one stage. <P>
+The alternatives are "security = user" or "security = server". <P>
+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".<P>
+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. <P>
+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". <P>
+See the <A HREF="#password server">password server</A> option for more
+details. <P>
+<B>Default:</B> security = SHARE <P>
+<B>Example:</B> security = USER <P>
+
+<H3><A NAME="server string">server string (G)</A></H3>
+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. <P>
+It also sets what will appear in browse lists next to the machine name. <P>
+A %v will be replaced with the Samba version number. <P>
+A %h will be replaced with the hostname. <P>
+<B>Default:</B> server string = Samba %v <P>
+<B>Example:</B> server string = University of GNUs Samba Server <P>
+
+<H3><A NAME="set directory">set directory (S)</A></H3>
+If 'set directory = No', then users of the service may not use the setdir
+command to change directory. <P>
+The setdir command is only implemented in the Digital Pathworks
+client. See the Pathworks documentation for details. <P>
+<B>Default:</B> set directory = No <P>
+<B>Example:</B> set directory = Yes <P>
+
+<H3><A NAME="shared mem size">shared mem size (G)</A></H3>
+This parameter is only useful when Samba has been compiled with
+FAST_SHARE_MODES. It specifies the size of the shared
+memory (in bytes) to use between smbd processes. You should never change
+this parameter unless you have studied the source and know what you are
+doing. This parameter defaults to 1024 multiplied by the setting of the
+maximum number of open files in the file local.h in the Samba source code.
+MAX_OPEN_FILES is normally set to 100, so this parameter defaults to 102400
+bytes. <P>
+<B>Default</B> shared mem size = 102400 <P>
+
+<H3><A NAME="smb passwd file">smb passwd file (G)</A></H3>
+This option sets the path to the encrypted smbpasswd file. This is a
+*VERY DANGEROUS OPTION* if the smb.conf is user writable. By default the
+path to the smbpasswd file is compiled into Samba. <P>
+
+<H3><A NAME="smbrun">smbrun (G)</A></H3>
+This sets the full path to the smbrun binary. This defaults to the value in
+the Makefile. <P>
+You must get this path right for many services to work correctly. <P>
+<B>Default:</B> taken from Makefile <P>
+<B>Example:</B> smbrun = /usr/local/samba/bin/smbrun <P>
+
+<H3><A NAME="share modes">share modes (S)</A></H3>
+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. <P>
+These open modes are not directly supported by UNIX, so they are simulated
+using lock files in the <A HREF="#lock dir">lock dir</A>. The "lock dir"
+specified in smb.conf must be readable by all users. <P>
+The share modes that are enabled by this option are DENY_DOS, DENY_ALL,
+DENY_READ, DENY_WRITE, DENY_NONE and DENY_FCB. <P>
+Enabling this option gives full share compatibility but may cost a bit of
+processing time on the UNIX server. They are enabled by default. <P>
+<B>Default:</B> share modes = Yes <P>
+<B>Example:</B> share modes = No <P>
+
+<H3><A NAME="short preserve case">short preserve case (S)</A></H3>
+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. <P>
+<B>Default:</B> short preserve case = No <P>
+See the section on <A HREF="#NAME MANGLING">NAME MANGLING</A> for a fuller
+discussion. <P>
+
+<H3><A NAME="socket address">socket address (G)</A></H3>
+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>
+By default samba will accept connections on any address. <P>
+<B>Example:</B> socket address = 192.168.2.20 <P>
+
+<H3><A NAME="socket options">socket options (G)</A></H3>
+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. <P>
+Socket options are controls on the networking layer of the operating systems
+which allow the connection to be tuned. <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. I strongly suggest you read the appropriate documentation for
+your operating system first (perhaps "man setsockopt" will help). <P>
+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@samba.anu.edu.au). <P>
+Any of the supported socket options may be combined in any way you like, as
+long as your OS allows it. <P>
+This is the list of socket options currently settable using this option: <P>
+SO_KEEPALIVE <BR>
+SO_REUSEADDR <BR>
+SO_BROADCAST <BR>
+TCP_NODELAY <BR>
+IPTOS_LOWDELAY <BR>
+IPTOS_THROUGHPUT <BR>
+SO_SNDBUF * <BR>
+SO_RCVBUF * <BR>
+SO_SNDLOWAT * <BR>
+SO_RCVLOWAT * <P>
+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. <P>
+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. <P>
+If you are on a local network then a sensible option might be <P>
+socket options = IPTOS_LOWDELAY <P>
+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 <P>
+socket options = IPTOS_LOWDELAY TCP_NODELAY <P>
+If you are on a wide area network then perhaps try setting IPTOS_THROUGHPUT. <P>
+Note that several of the options may cause your Samba server to fail
+completely. Use these options with caution! <P>
+<B>Default:</B> no socket options <P>
+<B>Example:</B> socket options = IPTOS_LOWDELAY <P>
+
+<H3><A NAME="status">status (G)</A></H3>
+This enables or disables logging of connections to a status
+file that <B>smbstatus</B> can read. <P>
+With this disabled <B>smbstatus</B> won't be able to tell you what connections
+are active. <P>
+<B>Default:</B> status = Yes <P>
+<B>Example:</B> status = No <P>
+
+<H3><A NAME="strict locking">strict locking (S)</A></H3>
+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. <P>
+When strict locking is "no" the server does file lock checks only when the
+client explicitly asks for them. <P>
+Well behaved clients always ask for lock checks when it is important,
+so in the vast majority of cases "strict locking = no" is preferable. <P>
+<B>Default:</B> strict locking = No <P>
+<B>Example:</B> strict locking = Yes <P>
+
+<H3><A NAME="strip dot">strip dot (G)</A></H3>
+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>
+<B>Default:</B> strip dot = No <P>
+<B>Example:</B> strip dot = Yes <P>
+
+<H3><A NAME="syslog">syslog (G)</A></H3>
+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 to
+LOG_NOTICE, debug level three maps onto LOG_INFO. The paramter sets the
+threshold for doing the mapping, all Samba debug messages above this threashold
+are mapped to syslog LOG_DEBUG messages. <P>
+<B>Default:</B> syslog = 1 <P>
+
+<H3><A NAME="syslog only">syslog only (G)</A></H3>
+If this parameter is set then Samba debug messages are logged
+into the system syslog only, and not to the debug log files. <P>
+<B>Default:</B> syslog only = no <P>
+
+<H3><A NAME="sync always">sync always (S)</A></H3>
+This is a boolean parameter that controls whether writes will always be
+written to stable storage before the write call returns. If this is No 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 Yes then every write will be followed by a fsync() call to ensure the
+data is written to disk. <P>
+<B>Default:</B> sync always = No <P>
+<B>Example:</B> sync always = Yes <P>
+
+<H3><A NAME="time offset">time offset (G)</A></H3>
+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>
+<B>Default:</B> time offset = 0 <P>
+<B>Example:</B> time offset = 60 <P>
+
+<H3><A NAME="time server">time server (G)</A></H3>
+This parameter determines if nmbd advertises itself as a time server to
+Windows clients. <P>
+<B>Default:</B> time server = No <P>
+<B>Example:</B> time server = Yes <P>
+
+<H3><A NAME="unix password sync">unix password sync (G)</A></H3>
+This boolean parameter controlls whether Samba attempts to synchronise the
+UNIX password with the SMB password when the encrypted SMB password in
+the smbpasswd file is changed. If this is set to Yes the
+<A HREF="#passwd program">passwd program</A>
+program is called *AS ROOT* - to allow the new UNIX password to be set
+without access to the old UNIX password (as the SMB password has change
+code has no access to the old password cleartext, only the new). By default
+this is set to No. <P>
+See also <A HREF="#passwd program">passwd program</A>,
+<A HREF="#passwd chat">passwd chat</A> <P>
+<B>Default:</B> unix password sync = No <P>
+<B>Example:</B> unix password sync = Yes <P>
+
+<H3><A NAME="unix realname">unix realname (G)</A></H3>
+This boolean parameter when set causes samba to supply the real name field
+from the unix password file to the client. This is useful for setting up mail
+clients and WWW browsers on systems used by more than one person. <P>
+<B>Default:</B> unix realname = No <P>
+<B>Example:</B> unix realname = Yes <P>
+
+<H3><A NAME="update encrypted">update encrypted (S)</A></H3>
+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". <P>
+In order for this parameter to work correctly the
+i<A HREF="#encrypt passwords">encrypt passwords</A> must be set to "No" when
+this parameter is set to "Yes". <P>
+Note that even when this parameter is set a user authenticating to smbd must
+still enter a valid password in order to connect correctly, and to update their
+hashed (smbpasswd) passwords. <P>
+<B>Default:</B> update encrypted = No <P>
+
+<H3><A NAME="use rhosts">use rhosts (S)</A></H3>
+<B>Default:</B> use rhosts = No <P>
+
+<H3><A NAME="username">username (S)</A></H3>
+A synonym for this parameter is 'user'. <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>
+The username= 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>
+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. <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>
+To restrict a service to a particular set of users you can use the
+<A HREF="#valid users">valid users</A> line. <P>
+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. <P>
+See the section below on
+<A HREF="#USERNAME/PASSWORD VALIDATION">USERNAME/PASSWORD VALIDATION</A>
+for more information on how this parameter determines access to the services.<P>
+<B>Default:</B> The guest account if a guest service, else the name of the service. <P>
+<B>Examples:</B>username = fredusername = fred, mary, jack, jane, @users, @pcgroup <P>
+
+<H3><A NAME="username level">username level (G)</A></H3>
+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>
+If this parameter is set to non-zero the behaviour changes. This parameter
+is a number that specifies the number of uppercase combinations to try whilst
+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'. <P>
+<B>Default:</B> username level = 0 <P>
+<B>Example:</B> username level = 5 <P>
+
+<H3><A NAME="username map">username map (G)</A></H3>
+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. <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. <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>
+If any line begins with a '#' or a ';' then it is ignored <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>
+For example to map from the name "admin" or "administrator" to the UNIX name
+"root" you would use <P>
+root = admin administrator <P>
+Or to map anyone in the UNIX group "system" to the UNIX name "sys" you would
+use <P>
+sys = @system <P>
+You can have as many mappings as you like in a username map file. <P>
+You can map Windows usernames that have spaces in them by using
+double quotes around the name. For example: <P>
+tridge = "Andrew Tridgell" <P>
+would map the windows username "Andrew Tridgell" to the unix username
+tridge. <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>
+!sys = mary fred guest = * <P>
+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 <A HREF="#password server">password server</A>
+(if you have one). The password server will receive whatever username the
+client supplies without modification. <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>
+<B>Default</B> no username map <P>
+<B>Example</B> username map = /usr/local/samba/lib/users.map <P>
+
+<H3><A NAME="valid chars">valid chars (S)</A></H3>
+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>
+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>
+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>
+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>
+valid chars = Z <BR>
+valid chars = z:Z <BR>
+valid chars = 0132:0172 <P>
+The last two examples above actually add two characters, and alter the
+uppercase and lowercase mappings appropriately. <P>
+Note that you MUST specify this parameter after the
+<A HREF="#client code page">client code page</A> parameter if you have both
+set. If "client code page" is set after the "valid chars" parameter the
+"valid chars" settings will be overwritten. <P>
+See also the <A HREF="#client code page">client code page</A> parameter. <P>
+<B>Default:</B> Samba defaults to using a reasonable set of valid characters
+for english systems <P>
+<B>Example:</B> valid chars = 0345:0305 0366:0326 0344:0304 <P>
+The above example allows filenames to have the swedish characters in them. <P>
+NOTE: It is actually quite difficult to correctly produce a "valid chars" line
+for a particular system. To automate the process tino@augsburg.net
+has written a package called "validchars" which will automatically produce
+a complete "valid chars" line for a given client system. Look in the examples
+subdirectory for this package. <P>
+
+<H3><A NAME="valid users">valid users (S)</A></H3>
+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. <P>
+If this is empty (the default) then any user can login. If a username is in
+both this list and the <A HREF="#invalid users">invalid users</A> list then
+access is denied for that user. <P>
+The current servicename is substituted for %S. This is useful in the [homes]
+section. <P>
+See also <A HREF="#invalid users">invalid users</A> <P>
+<B>Default</B> No valid users list. (anyone can login) <P>
+<B>Example</B> valid users = greg, @pcusers <P>
+
+<H3><A NAME="veto files">veto files (S)</A></H3>
+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>
+Each entry must be a unix path, not a DOS path and must not include the
+unix directory separator "/". <P>
+Note that the case sensitivity option is applicable in vetoing files. <P>
+One feature of the veto files parameter that it is important to be aware of,
+is that if a directory contains nothing but files that match the veto files
+parameter (which means that Windows/DOS clients cannot ever see them) is
+deleted, the veto files within that directory *are automatically deleted*
+along with it, if the user has UNIX permissions to do so.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>
+See also <A HREF="#hide files">hide files</A> and
+<A HREF="#case sensitive">case sensitive</A> <P>
+<B>Default</B> No files or directories are vetoed. <P>
+<B>Examples</B> Example 1. Veto any files containing the word Security, any
+ending in .tmp, and any directory containing the word root. <P>
+veto files = /*Security*/*.tmp/*root*/ <P>
+Example 2. Veto the Apple specific files that a NetAtalk server creates. <P>
+veto files = /.AppleDouble/.bin/.AppleDesktop/Network Trash Folder/ <P>
+
+<H3><A NAME="veto oplock files">veto oplock files (S)</A></H3>
+This parameter is only valid when the <A HREF="#oplocks">oplocks</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="#veto files">veto files</A> parameter. <P>
+<B>Default</B> No files are vetoed for oplock grants. <P>
+<B>Examples</B> 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 .SEM. 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>
+veto oplock files = /*.SEM/ <P>
+
+<H3><A NAME="volume">volume (S)</A></H3>
+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>
+The default is the name of the share <P>
+
+<H3><A NAME="wide links">wide links (S)</A></H3>
+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>
+<B>Default:</B> wide links = Yes <P>
+<B>Example:</B> wide links = No <P>
+
+<H3><A NAME="wins proxy">wins proxy (G)</A></H3>
+This is a boolean that controls if nmbd will respond to broadcast name queries
+on behalf of other hosts. You may need to set this to no for some older
+clients. <P>
+<B>Default:</B> wins proxy = No <P>
+
+<H3><A NAME="wins server">wins server (G)</A></H3>
+This specifies the DNS name (or IP address) of the WINS server that Samba
+should register with. If you have a WINS server on your network then you
+should set this to the WINS servers name. <P>
+You should point this at your WINS server if you have a multi-subnetted
+network. <P>
+<B>Default:</B> wins server = <P>
+
+<H3><A NAME="wins support">wins support (G)</A></H3>
+This boolean controls if the nmbd process in Samba will act as a WINS server.
+You should not set this to Yes unless you have a multi-subnetted network and
+you wish a particular nmbd to be your WINS server. Note that you should
+*NEVER* set this to Yes on more than one machine in your network. <P>
+<B>Default:</B> wins support = No <P>
+
+<H3><A NAME="workgroup">workgroup (G)</A></H3>
+This controls what workgroup your server will appear to be in when queried by
+clients. <P>
+<B>Default:</B> set in the Makefile <P>
+<B>Example:</B> workgroup = MYGROUP <P>
+
+<H3><A NAME="write list">write list (S)</A></H3>
+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="#writable">writable</A> option is set to.
+The list can include group names using the @group syntax. <P>
+Note that if a user is in both the read list and the write list then they
+will be given write access. <P>
+See also the <A HREF="#read list">read list</A> option <P>
+<B>Default:</B> write list = <P>
+<B>Example:</B> write list = admin, root, @staff <P>
+
+<H3><A NAME="write raw">write raw (G)</A></H3>
+This parameter controls whether or not the server will support raw writes
+when transferring data from clients. <P>
+<B>Default:</B> write raw = Yes <P>
+<B>Example:</B> write raw = No <P>
+
+<H3><A NAME="USERNAME/PASSWORD VALIDATION">USERNAME/PASSWORD VALIDATION</A></H3>
+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. <P>
+If the service is marked "<A HREF="#guest only">guest only</A> = yes" then
+steps 1 to 5 are skipped <P>
+Step 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%username method of passing a username. <P>
+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. <P>
+Step 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. <P>
+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 "<A HREF="#revalidate">revalidate</A> = yes"
+for this service. <P>
+Step 5: If a "<A HREF="#username">username</A> = " 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 system's password checking) with
+one of the usernames from the username= field then the connection is made as
+the username in the "username=" line. If one of the username in the username=
+list begins with a @ then that name expands to a list of names in the group
+of the same name. <P>
+Step 6: If the service is a guest service then a connection is made as the
+username given in the "<A HREF="#guest account">guest account</A> =" for the
+service, irrespective of the supplied password.<P>
+
+<H3><A NAME="NAME MANGLING">NAME MANGLING </A></H3>
+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>
+There are several options that control the way mangling is
+performed, and they are grouped here rather than listed separately. <P>
+All of these options can be set separately for each service (or globally,
+of course). <P>
+The options are: <P>
+"<A HREF="#mangle case">mangle case</A> = 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. <P>
+"<A HREF="#case sensitive">case sensitive</A> = 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. <P>
+"<A HREF="#default case">default case</A> = upper/lower" controls what the
+default case is for new filenames. Default lower. <P>
+"<A HREF="#preserve case">preserve case</A> = 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. <P>
+"<A HREF="#short preserve case">short preserve case</A> = 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. <P>
+
+</BODY>
+</HTML>
+
+
diff --git a/swat/help/welcome.html b/swat/help/welcome.html
new file mode 100644
index 00000000000..a1545ac9d7f
--- /dev/null
+++ b/swat/help/welcome.html
@@ -0,0 +1,74 @@
+Welcome to SWAT!<p>
+
+This is a online demonstration of the current version of the Samba Web
+Administration Tool. This tool is still being written so you'll find
+it looks very rough at this stage.<p>
+
+Normally this opening page would contain the (as yet unwritten) welcome
+blurb for SWAT, giving basic instructions on how to use it. I've put
+this bit of waffle in its place for the moment. <p>
+
+Also note that SWAT normally demands authentication before showing you
+this page, otherwise anyone could modify your smb.conf! I've disabled
+that for this demo.<p>
+
+<H2>Features</H2>
+
+Here are some of the features we want to eventually incorporate.<p>
+
+<ul>
+<li> manage smbpasswd (add/delete users, change passwords etc)
+<li> be able to run the disgnosis steps from DIAGNOSIS.txt
+<li> wizard style config building
+</ul>
+
+There are also some obvious flaws with what has already been done:
+
+<ul>
+<li> help is ghastly
+<li> ordering of parameters needs to be looked at
+<li> images need redoing
+</ul>
+
+On the positive side, here are some good features of SWAT:
+
+<ul>
+<li> built in mini web server so you don't need a web server installed to
+manage a Samba server, you just need a browser
+<li> links to loadparm.c so it automatically makes available new
+parameters as they are added to Samba.
+<li> it's quite small (around 500 lines of code currently)
+<li> layout and dialog building is done automatically based on the type
+fields in loadparm.c
+</ul>
+
+
+<H2>Installation</H2>
+
+Before you install SWAT you need to realise that it is still work in
+progress. It does work but don't be totally surprised if you hit
+problems. Also make sure you are prepared to give us some feedback.<p>
+
+If you still want to install it then you will need to fetch the latest
+version of Samba via anonymous CVS. See <A
+HREF="http://samba.anu.edu.au/cvs.html">http://samba.anu.edu.au/cvs.html</A>. Then
+build and install Samba as usual and read the swat/README file that
+comes with the source.
+
+<H2>Feedback</H2>
+
+Join the <A
+HREF="http://samba.anu.edu.au/listproc/">samba-technical</A> mailing
+list if you want to discuss SWAT.
+
+-- <p>
+<A HREF="http://samba.anu.edu.au/~tridge">Andrew Tridgell</A>
+
+
+
+
+
+
+
+
+
diff --git a/swat/images/background.gif b/swat/images/background.gif
new file mode 100644
index 00000000000..b3484629654
--- /dev/null
+++ b/swat/images/background.gif
Binary files differ
diff --git a/swat/images/background.jpg b/swat/images/background.jpg
new file mode 100644
index 00000000000..e84e11fbefc
--- /dev/null
+++ b/swat/images/background.jpg
Binary files differ
diff --git a/swat/images/globals.gif b/swat/images/globals.gif
new file mode 100644
index 00000000000..03bc4baaf5e
--- /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..fcb7d383171
--- /dev/null
+++ b/swat/images/home.gif
Binary files differ
diff --git a/swat/images/printers.gif b/swat/images/printers.gif
new file mode 100644
index 00000000000..68f4a34dafb
--- /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..79ac7353c7b
--- /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..1b4ee8a9a56
--- /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..081a62e6566
--- /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">